1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
29 #include "SMESH_MeshEditor.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
53 #include "utilities.h"
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
103 using namespace SMESH::Controls;
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
110 //=======================================================================
111 //function : SMESH_MeshEditor
113 //=======================================================================
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116 :myMesh( theMesh ) // theMesh may be NULL
120 //=======================================================================
124 //=======================================================================
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128 const SMDSAbs_ElementType type,
132 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133 SMDS_MeshElement* e = 0;
134 int nbnode = node.size();
135 SMESHDS_Mesh* mesh = GetMeshDS();
140 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141 else e = mesh->AddFace (node[0], node[1], node[2] );
143 else if (nbnode == 4) {
144 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
147 else if (nbnode == 6) {
148 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149 node[4], node[5], ID);
150 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
153 else if (nbnode == 8) {
154 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155 node[4], node[5], node[6], node[7], ID);
156 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
157 node[4], node[5], node[6], node[7] );
160 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
161 else e = mesh->AddPolygonalFace (node );
168 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
171 else if (nbnode == 5) {
172 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
174 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
177 else if (nbnode == 6) {
178 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179 node[4], node[5], ID);
180 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
183 else if (nbnode == 8) {
184 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185 node[4], node[5], node[6], node[7], ID);
186 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
187 node[4], node[5], node[6], node[7] );
189 else if (nbnode == 10) {
190 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191 node[4], node[5], node[6], node[7],
192 node[8], node[9], ID);
193 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
194 node[4], node[5], node[6], node[7],
197 else if (nbnode == 13) {
198 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199 node[4], node[5], node[6], node[7],
200 node[8], node[9], node[10],node[11],
202 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
203 node[4], node[5], node[6], node[7],
204 node[8], node[9], node[10],node[11],
207 else if (nbnode == 15) {
208 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209 node[4], node[5], node[6], node[7],
210 node[8], node[9], node[10],node[11],
211 node[12],node[13],node[14],ID);
212 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
213 node[4], node[5], node[6], node[7],
214 node[8], node[9], node[10],node[11],
215 node[12],node[13],node[14] );
217 else if (nbnode == 20) {
218 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219 node[4], node[5], node[6], node[7],
220 node[8], node[9], node[10],node[11],
221 node[12],node[13],node[14],node[15],
222 node[16],node[17],node[18],node[19],ID);
223 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
224 node[4], node[5], node[6], node[7],
225 node[8], node[9], node[10],node[11],
226 node[12],node[13],node[14],node[15],
227 node[16],node[17],node[18],node[19] );
234 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
235 else e = mesh->AddEdge (node[0], node[1] );
237 else if ( nbnode == 3 ) {
238 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
239 else e = mesh->AddEdge (node[0], node[1], node[2] );
243 case SMDSAbs_0DElement:
245 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
246 else e = mesh->Add0DElement (node[0] );
251 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
252 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
257 if ( e ) myLastCreatedElems.Append( e );
261 //=======================================================================
265 //=======================================================================
267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
268 const SMDSAbs_ElementType type,
272 vector<const SMDS_MeshNode*> nodes;
273 nodes.reserve( nodeIDs.size() );
274 vector<int>::const_iterator id = nodeIDs.begin();
275 while ( id != nodeIDs.end() ) {
276 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
277 nodes.push_back( node );
281 return AddElement( nodes, type, isPoly, ID );
284 //=======================================================================
286 //purpose : Remove a node or an element.
287 // Modify a compute state of sub-meshes which become empty
288 //=======================================================================
290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
293 myLastCreatedElems.Clear();
294 myLastCreatedNodes.Clear();
296 SMESHDS_Mesh* aMesh = GetMeshDS();
297 set< SMESH_subMesh *> smmap;
300 list<int>::const_iterator it = theIDs.begin();
301 for ( ; it != theIDs.end(); it++ ) {
302 const SMDS_MeshElement * elem;
304 elem = aMesh->FindNode( *it );
306 elem = aMesh->FindElement( *it );
310 // Notify VERTEX sub-meshes about modification
312 const SMDS_MeshNode* node = cast2Node( elem );
313 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
314 if ( int aShapeID = node->getshapeId() )
315 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
318 // Find sub-meshes to notify about modification
319 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
320 // while ( nodeIt->more() ) {
321 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
322 // const SMDS_PositionPtr& aPosition = node->GetPosition();
323 // if ( aPosition.get() ) {
324 // if ( int aShapeID = aPosition->GetShapeId() ) {
325 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
326 // smmap.insert( sm );
333 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
335 aMesh->RemoveElement( elem );
339 // Notify sub-meshes about modification
340 if ( !smmap.empty() ) {
341 set< SMESH_subMesh *>::iterator smIt;
342 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
343 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
346 // // Check if the whole mesh becomes empty
347 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
348 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
353 //=======================================================================
354 //function : FindShape
355 //purpose : Return an index of the shape theElem is on
356 // or zero if a shape not found
357 //=======================================================================
359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
361 myLastCreatedElems.Clear();
362 myLastCreatedNodes.Clear();
364 SMESHDS_Mesh * aMesh = GetMeshDS();
365 if ( aMesh->ShapeToMesh().IsNull() )
368 if ( theElem->GetType() == SMDSAbs_Node )
370 int aShapeID = theElem->getshapeId();
377 TopoDS_Shape aShape; // the shape a node is on
378 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
379 while ( nodeIt->more() ) {
380 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
381 int aShapeID = node->getshapeId();
383 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
385 if ( sm->Contains( theElem ))
387 if ( aShape.IsNull() )
388 aShape = aMesh->IndexToShape( aShapeID );
391 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
396 // None of nodes is on a proper shape,
397 // find the shape among ancestors of aShape on which a node is
398 if ( aShape.IsNull() ) {
399 //MESSAGE ("::FindShape() - NONE node is on shape")
402 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
403 for ( ; ancIt.More(); ancIt.Next() ) {
404 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
405 if ( sm && sm->Contains( theElem ))
406 return aMesh->ShapeToIndex( ancIt.Value() );
409 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
413 //=======================================================================
414 //function : IsMedium
416 //=======================================================================
418 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
419 const SMDSAbs_ElementType typeToCheck)
421 bool isMedium = false;
422 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
423 while (it->more() && !isMedium ) {
424 const SMDS_MeshElement* elem = it->next();
425 isMedium = elem->IsMediumNode(node);
430 //=======================================================================
431 //function : ShiftNodesQuadTria
433 // Shift nodes in the array corresponded to quadratic triangle
434 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
435 //=======================================================================
436 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
438 const SMDS_MeshNode* nd1 = aNodes[0];
439 aNodes[0] = aNodes[1];
440 aNodes[1] = aNodes[2];
442 const SMDS_MeshNode* nd2 = aNodes[3];
443 aNodes[3] = aNodes[4];
444 aNodes[4] = aNodes[5];
448 //=======================================================================
449 //function : GetNodesFromTwoTria
451 // Shift nodes in the array corresponded to quadratic triangle
452 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
453 //=======================================================================
454 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
455 const SMDS_MeshElement * theTria2,
456 const SMDS_MeshNode* N1[],
457 const SMDS_MeshNode* N2[])
459 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
462 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
465 if(it->more()) return false;
466 it = theTria2->nodesIterator();
469 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
472 if(it->more()) return false;
474 int sames[3] = {-1,-1,-1};
486 if(nbsames!=2) return false;
488 ShiftNodesQuadTria(N1);
490 ShiftNodesQuadTria(N1);
493 i = sames[0] + sames[1] + sames[2];
495 ShiftNodesQuadTria(N2);
497 // now we receive following N1 and N2 (using numeration as above image)
498 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
499 // i.e. first nodes from both arrays determ new diagonal
503 //=======================================================================
504 //function : InverseDiag
505 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
506 // but having other common link.
507 // Return False if args are improper
508 //=======================================================================
510 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
511 const SMDS_MeshElement * theTria2 )
513 MESSAGE("InverseDiag");
514 myLastCreatedElems.Clear();
515 myLastCreatedNodes.Clear();
517 if (!theTria1 || !theTria2)
520 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
521 if (!F1) return false;
522 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
523 if (!F2) return false;
524 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
525 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
527 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
528 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
532 // put nodes in array and find out indices of the same ones
533 const SMDS_MeshNode* aNodes [6];
534 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
536 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
537 while ( it->more() ) {
538 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
540 if ( i > 2 ) // theTria2
541 // find same node of theTria1
542 for ( int j = 0; j < 3; j++ )
543 if ( aNodes[ i ] == aNodes[ j ]) {
552 return false; // theTria1 is not a triangle
553 it = theTria2->nodesIterator();
555 if ( i == 6 && it->more() )
556 return false; // theTria2 is not a triangle
559 // find indices of 1,2 and of A,B in theTria1
560 int iA = 0, iB = 0, i1 = 0, i2 = 0;
561 for ( i = 0; i < 6; i++ ) {
562 if ( sameInd [ i ] == 0 ) {
571 // nodes 1 and 2 should not be the same
572 if ( aNodes[ i1 ] == aNodes[ i2 ] )
576 aNodes[ iA ] = aNodes[ i2 ];
578 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
580 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
581 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
585 } // end if(F1 && F2)
587 // check case of quadratic faces
588 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
590 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
594 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
595 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
603 const SMDS_MeshNode* N1 [6];
604 const SMDS_MeshNode* N2 [6];
605 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
607 // now we receive following N1 and N2 (using numeration as above image)
608 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
609 // i.e. first nodes from both arrays determ new diagonal
611 const SMDS_MeshNode* N1new [6];
612 const SMDS_MeshNode* N2new [6];
625 // replaces nodes in faces
626 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
627 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
632 //=======================================================================
633 //function : findTriangles
634 //purpose : find triangles sharing theNode1-theNode2 link
635 //=======================================================================
637 static bool findTriangles(const SMDS_MeshNode * theNode1,
638 const SMDS_MeshNode * theNode2,
639 const SMDS_MeshElement*& theTria1,
640 const SMDS_MeshElement*& theTria2)
642 if ( !theNode1 || !theNode2 ) return false;
644 theTria1 = theTria2 = 0;
646 set< const SMDS_MeshElement* > emap;
647 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
649 const SMDS_MeshElement* elem = it->next();
650 if ( elem->NbNodes() == 3 )
653 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
655 const SMDS_MeshElement* elem = it->next();
656 if ( emap.find( elem ) != emap.end() ) {
658 // theTria1 must be element with minimum ID
659 if( theTria1->GetID() < elem->GetID() ) {
673 return ( theTria1 && theTria2 );
676 //=======================================================================
677 //function : InverseDiag
678 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
679 // with ones built on the same 4 nodes but having other common link.
680 // Return false if proper faces not found
681 //=======================================================================
683 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
684 const SMDS_MeshNode * theNode2)
686 myLastCreatedElems.Clear();
687 myLastCreatedNodes.Clear();
689 MESSAGE( "::InverseDiag()" );
691 const SMDS_MeshElement *tr1, *tr2;
692 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
695 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
696 if (!F1) return false;
697 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
698 if (!F2) return false;
699 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
700 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
702 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
703 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
707 // put nodes in array
708 // and find indices of 1,2 and of A in tr1 and of B in tr2
709 int i, iA1 = 0, i1 = 0;
710 const SMDS_MeshNode* aNodes1 [3];
711 SMDS_ElemIteratorPtr it;
712 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
713 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
714 if ( aNodes1[ i ] == theNode1 )
715 iA1 = i; // node A in tr1
716 else if ( aNodes1[ i ] != theNode2 )
720 const SMDS_MeshNode* aNodes2 [3];
721 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
722 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
723 if ( aNodes2[ i ] == theNode2 )
724 iB2 = i; // node B in tr2
725 else if ( aNodes2[ i ] != theNode1 )
729 // nodes 1 and 2 should not be the same
730 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
734 aNodes1[ iA1 ] = aNodes2[ i2 ];
736 aNodes2[ iB2 ] = aNodes1[ i1 ];
738 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
739 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
744 // check case of quadratic faces
745 return InverseDiag(tr1,tr2);
748 //=======================================================================
749 //function : getQuadrangleNodes
750 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
751 // fusion of triangles tr1 and tr2 having shared link on
752 // theNode1 and theNode2
753 //=======================================================================
755 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
756 const SMDS_MeshNode * theNode1,
757 const SMDS_MeshNode * theNode2,
758 const SMDS_MeshElement * tr1,
759 const SMDS_MeshElement * tr2 )
761 if( tr1->NbNodes() != tr2->NbNodes() )
763 // find the 4-th node to insert into tr1
764 const SMDS_MeshNode* n4 = 0;
765 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
767 while ( !n4 && i<3 ) {
768 const SMDS_MeshNode * n = cast2Node( it->next() );
770 bool isDiag = ( n == theNode1 || n == theNode2 );
774 // Make an array of nodes to be in a quadrangle
775 int iNode = 0, iFirstDiag = -1;
776 it = tr1->nodesIterator();
779 const SMDS_MeshNode * n = cast2Node( it->next() );
781 bool isDiag = ( n == theNode1 || n == theNode2 );
783 if ( iFirstDiag < 0 )
785 else if ( iNode - iFirstDiag == 1 )
786 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
788 else if ( n == n4 ) {
789 return false; // tr1 and tr2 should not have all the same nodes
791 theQuadNodes[ iNode++ ] = n;
793 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
794 theQuadNodes[ iNode ] = n4;
799 //=======================================================================
800 //function : DeleteDiag
801 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
802 // with a quadrangle built on the same 4 nodes.
803 // Return false if proper faces not found
804 //=======================================================================
806 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
807 const SMDS_MeshNode * theNode2)
809 myLastCreatedElems.Clear();
810 myLastCreatedNodes.Clear();
812 MESSAGE( "::DeleteDiag()" );
814 const SMDS_MeshElement *tr1, *tr2;
815 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
818 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
819 if (!F1) return false;
820 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
821 if (!F2) return false;
822 SMESHDS_Mesh * aMesh = GetMeshDS();
824 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
825 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
827 const SMDS_MeshNode* aNodes [ 4 ];
828 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
831 const SMDS_MeshElement* newElem = 0;
832 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
833 myLastCreatedElems.Append(newElem);
834 AddToSameGroups( newElem, tr1, aMesh );
835 int aShapeId = tr1->getshapeId();
838 aMesh->SetMeshElementOnShape( newElem, aShapeId );
840 aMesh->RemoveElement( tr1 );
841 aMesh->RemoveElement( tr2 );
846 // check case of quadratic faces
847 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
849 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
853 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
854 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
862 const SMDS_MeshNode* N1 [6];
863 const SMDS_MeshNode* N2 [6];
864 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
866 // now we receive following N1 and N2 (using numeration as above image)
867 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
868 // i.e. first nodes from both arrays determ new diagonal
870 const SMDS_MeshNode* aNodes[8];
880 const SMDS_MeshElement* newElem = 0;
881 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
882 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
883 myLastCreatedElems.Append(newElem);
884 AddToSameGroups( newElem, tr1, aMesh );
885 int aShapeId = tr1->getshapeId();
888 aMesh->SetMeshElementOnShape( newElem, aShapeId );
890 aMesh->RemoveElement( tr1 );
891 aMesh->RemoveElement( tr2 );
893 // remove middle node (9)
894 GetMeshDS()->RemoveNode( N1[4] );
899 //=======================================================================
900 //function : Reorient
901 //purpose : Reverse theElement orientation
902 //=======================================================================
904 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
907 myLastCreatedElems.Clear();
908 myLastCreatedNodes.Clear();
912 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
913 if ( !it || !it->more() )
916 switch ( theElem->GetType() ) {
920 if(!theElem->IsQuadratic()) {
921 int i = theElem->NbNodes();
922 vector<const SMDS_MeshNode*> aNodes( i );
924 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
925 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
928 // quadratic elements
929 if(theElem->GetType()==SMDSAbs_Edge) {
930 vector<const SMDS_MeshNode*> aNodes(3);
931 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
932 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
933 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
934 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
937 int nbn = theElem->NbNodes();
938 vector<const SMDS_MeshNode*> aNodes(nbn);
939 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
941 for(; i<nbn/2; i++) {
942 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
944 for(i=0; i<nbn/2; i++) {
945 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
947 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
951 case SMDSAbs_Volume: {
952 if (theElem->IsPoly()) {
953 // TODO reorient vtk polyhedron
954 MESSAGE("reorient vtk polyhedron ?");
955 const SMDS_VtkVolume* aPolyedre =
956 dynamic_cast<const SMDS_VtkVolume*>( theElem );
958 MESSAGE("Warning: bad volumic element");
962 int nbFaces = aPolyedre->NbFaces();
963 vector<const SMDS_MeshNode *> poly_nodes;
964 vector<int> quantities (nbFaces);
966 // reverse each face of the polyedre
967 for (int iface = 1; iface <= nbFaces; iface++) {
968 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
969 quantities[iface - 1] = nbFaceNodes;
971 for (inode = nbFaceNodes; inode >= 1; inode--) {
972 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
973 poly_nodes.push_back(curNode);
977 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
981 SMDS_VolumeTool vTool;
982 if ( !vTool.Set( theElem ))
985 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
986 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
995 //=======================================================================
996 //function : getBadRate
998 //=======================================================================
1000 static double getBadRate (const SMDS_MeshElement* theElem,
1001 SMESH::Controls::NumericalFunctorPtr& theCrit)
1003 SMESH::Controls::TSequenceOfXYZ P;
1004 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1006 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1007 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1010 //=======================================================================
1011 //function : QuadToTri
1012 //purpose : Cut quadrangles into triangles.
1013 // theCrit is used to select a diagonal to cut
1014 //=======================================================================
1016 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1017 SMESH::Controls::NumericalFunctorPtr theCrit)
1019 myLastCreatedElems.Clear();
1020 myLastCreatedNodes.Clear();
1022 MESSAGE( "::QuadToTri()" );
1024 if ( !theCrit.get() )
1027 SMESHDS_Mesh * aMesh = GetMeshDS();
1029 Handle(Geom_Surface) surface;
1030 SMESH_MesherHelper helper( *GetMesh() );
1032 TIDSortedElemSet::iterator itElem;
1033 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1034 const SMDS_MeshElement* elem = *itElem;
1035 if ( !elem || elem->GetType() != SMDSAbs_Face )
1037 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1040 // retrieve element nodes
1041 const SMDS_MeshNode* aNodes [8];
1042 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1044 while ( itN->more() )
1045 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1047 // compare two sets of possible triangles
1048 double aBadRate1, aBadRate2; // to what extent a set is bad
1049 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1050 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1051 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1053 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1054 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1055 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1057 int aShapeId = FindShape( elem );
1058 const SMDS_MeshElement* newElem1 = 0;
1059 const SMDS_MeshElement* newElem2 = 0;
1061 if( !elem->IsQuadratic() ) {
1063 // split liner quadrangle
1064 if ( aBadRate1 <= aBadRate2 ) {
1065 // tr1 + tr2 is better
1066 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1067 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1070 // tr3 + tr4 is better
1071 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1072 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1077 // split quadratic quadrangle
1079 // get surface elem is on
1080 if ( aShapeId != helper.GetSubShapeID() ) {
1084 shape = aMesh->IndexToShape( aShapeId );
1085 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1086 TopoDS_Face face = TopoDS::Face( shape );
1087 surface = BRep_Tool::Surface( face );
1088 if ( !surface.IsNull() )
1089 helper.SetSubShape( shape );
1093 const SMDS_MeshNode* aNodes [8];
1094 const SMDS_MeshNode* inFaceNode = 0;
1095 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1097 while ( itN->more() ) {
1098 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1099 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1100 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1102 inFaceNode = aNodes[ i-1 ];
1105 // find middle point for (0,1,2,3)
1106 // and create a node in this point;
1108 if ( surface.IsNull() ) {
1110 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1114 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1117 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1119 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1121 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1122 myLastCreatedNodes.Append(newN);
1124 // create a new element
1125 const SMDS_MeshNode* N[6];
1126 if ( aBadRate1 <= aBadRate2 ) {
1133 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1134 aNodes[6], aNodes[7], newN );
1135 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1136 newN, aNodes[4], aNodes[5] );
1145 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1146 aNodes[7], aNodes[4], newN );
1147 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1148 newN, aNodes[5], aNodes[6] );
1152 // care of a new element
1154 myLastCreatedElems.Append(newElem1);
1155 myLastCreatedElems.Append(newElem2);
1156 AddToSameGroups( newElem1, elem, aMesh );
1157 AddToSameGroups( newElem2, elem, aMesh );
1159 // put a new triangle on the same shape
1162 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1163 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1165 aMesh->RemoveElement( elem );
1170 //=======================================================================
1171 //function : BestSplit
1172 //purpose : Find better diagonal for cutting.
1173 //=======================================================================
1175 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1176 SMESH::Controls::NumericalFunctorPtr theCrit)
1178 myLastCreatedElems.Clear();
1179 myLastCreatedNodes.Clear();
1184 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1187 if( theQuad->NbNodes()==4 ||
1188 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1190 // retrieve element nodes
1191 const SMDS_MeshNode* aNodes [4];
1192 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1194 //while (itN->more())
1196 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1198 // compare two sets of possible triangles
1199 double aBadRate1, aBadRate2; // to what extent a set is bad
1200 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1201 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1202 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1204 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1205 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1206 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1208 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1209 return 1; // diagonal 1-3
1211 return 2; // diagonal 2-4
1218 // Methods of splitting volumes into tetra
1220 const int theHexTo5_1[5*4+1] =
1222 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1224 const int theHexTo5_2[5*4+1] =
1226 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1228 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1230 const int theHexTo6_1[6*4+1] =
1232 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
1234 const int theHexTo6_2[6*4+1] =
1236 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
1238 const int theHexTo6_3[6*4+1] =
1240 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
1242 const int theHexTo6_4[6*4+1] =
1244 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
1246 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1248 const int thePyraTo2_1[2*4+1] =
1250 0, 1, 2, 4, 0, 2, 3, 4, -1
1252 const int thePyraTo2_2[2*4+1] =
1254 1, 2, 3, 4, 1, 3, 0, 4, -1
1256 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1258 const int thePentaTo3_1[3*4+1] =
1260 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1262 const int thePentaTo3_2[3*4+1] =
1264 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1266 const int thePentaTo3_3[3*4+1] =
1268 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1270 const int thePentaTo3_4[3*4+1] =
1272 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1274 const int thePentaTo3_5[3*4+1] =
1276 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1278 const int thePentaTo3_6[3*4+1] =
1280 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1282 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1283 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1285 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1288 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1289 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1290 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1295 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1296 bool _baryNode; //!< additional node is to be created at cell barycenter
1297 bool _ownConn; //!< to delete _connectivity in destructor
1298 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1300 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1301 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1302 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1303 bool hasFacet( const TTriangleFacet& facet ) const
1305 const int* tetConn = _connectivity;
1306 for ( ; tetConn[0] >= 0; tetConn += 4 )
1307 if (( facet.contains( tetConn[0] ) +
1308 facet.contains( tetConn[1] ) +
1309 facet.contains( tetConn[2] ) +
1310 facet.contains( tetConn[3] )) == 3 )
1316 //=======================================================================
1318 * \brief return TSplitMethod for the given element
1320 //=======================================================================
1322 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1324 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1326 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1327 // an edge and a face barycenter; tertaherdons are based on triangles and
1328 // a volume barycenter
1329 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1331 // Find out how adjacent volumes are split
1333 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1334 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1335 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1337 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1338 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1339 if ( nbNodes < 4 ) continue;
1341 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1342 const int* nInd = vol.GetFaceNodesIndices( iF );
1345 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1346 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1347 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1348 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1352 int iCom = 0; // common node of triangle faces to split into
1353 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1355 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1356 nInd[ iQ * ( (iCom+1)%nbNodes )],
1357 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1358 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1359 nInd[ iQ * ( (iCom+2)%nbNodes )],
1360 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1361 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1363 triaSplits.push_back( t012 );
1364 triaSplits.push_back( t023 );
1369 if ( !triaSplits.empty() )
1370 hasAdjacentSplits = true;
1373 // Among variants of split method select one compliant with adjacent volumes
1375 TSplitMethod method;
1376 if ( !vol.Element()->IsPoly() && !is24TetMode )
1378 int nbVariants = 2, nbTet = 0;
1379 const int** connVariants = 0;
1380 switch ( vol.Element()->GetEntityType() )
1382 case SMDSEntity_Hexa:
1383 case SMDSEntity_Quad_Hexa:
1384 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1385 connVariants = theHexTo5, nbTet = 5;
1387 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1389 case SMDSEntity_Pyramid:
1390 case SMDSEntity_Quad_Pyramid:
1391 connVariants = thePyraTo2; nbTet = 2;
1393 case SMDSEntity_Penta:
1394 case SMDSEntity_Quad_Penta:
1395 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1400 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1402 // check method compliancy with adjacent tetras,
1403 // all found splits must be among facets of tetras described by this method
1404 method = TSplitMethod( nbTet, connVariants[variant] );
1405 if ( hasAdjacentSplits && method._nbTetra > 0 )
1407 bool facetCreated = true;
1408 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1410 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1411 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1412 facetCreated = method.hasFacet( *facet );
1414 if ( !facetCreated )
1415 method = TSplitMethod(0); // incompatible method
1419 if ( method._nbTetra < 1 )
1421 // No standard method is applicable, use a generic solution:
1422 // each facet of a volume is split into triangles and
1423 // each of triangles and a volume barycenter form a tetrahedron.
1425 int* connectivity = new int[ maxTetConnSize + 1 ];
1426 method._connectivity = connectivity;
1427 method._ownConn = true;
1428 method._baryNode = true;
1431 int baryCenInd = vol.NbNodes();
1432 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1434 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1435 const int* nInd = vol.GetFaceNodesIndices( iF );
1436 // find common node of triangle facets of tetra to create
1437 int iCommon = 0; // index in linear numeration
1438 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1439 if ( !triaSplits.empty() )
1442 const TTriangleFacet* facet = &triaSplits.front();
1443 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1444 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1445 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1448 else if ( nbNodes > 3 && !is24TetMode )
1450 // find the best method of splitting into triangles by aspect ratio
1451 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1452 map< double, int > badness2iCommon;
1453 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1454 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1455 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1456 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1458 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1459 nodes[ iQ*((iLast-1)%nbNodes)],
1460 nodes[ iQ*((iLast )%nbNodes)]);
1461 double badness = getBadRate( &tria, aspectRatio );
1462 badness2iCommon.insert( make_pair( badness, iCommon ));
1464 // use iCommon with lowest badness
1465 iCommon = badness2iCommon.begin()->second;
1467 if ( iCommon >= nbNodes )
1468 iCommon = 0; // something wrong
1470 // fill connectivity of tetrahedra based on a current face
1471 int nbTet = nbNodes - 2;
1472 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1474 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1475 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1477 for ( int i = 0; i < nbTet; ++i )
1479 int i1 = i, i2 = (i+1) % nbNodes;
1480 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1481 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1482 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1483 connectivity[ connSize++ ] = faceBaryCenInd;
1484 connectivity[ connSize++ ] = baryCenInd;
1489 for ( int i = 0; i < nbTet; ++i )
1491 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1492 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1493 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1494 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1495 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1496 connectivity[ connSize++ ] = baryCenInd;
1499 method._nbTetra += nbTet;
1501 connectivity[ connSize++ ] = -1;
1505 //================================================================================
1507 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1509 //================================================================================
1511 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1513 // find the tetrahedron including the three nodes of facet
1514 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1515 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1516 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1517 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1518 while ( volIt1->more() )
1520 const SMDS_MeshElement* v = volIt1->next();
1521 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1523 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1524 while ( volIt2->more() )
1525 if ( v != volIt2->next() )
1527 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1528 while ( volIt3->more() )
1529 if ( v == volIt3->next() )
1535 //=======================================================================
1537 * \brief A key of a face of volume
1539 //=======================================================================
1541 struct TVolumeFaceKey: pair< int, pair< int, int> >
1543 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1545 TIDSortedNodeSet sortedNodes;
1546 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1547 int nbNodes = vol.NbFaceNodes( iF );
1548 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1549 for ( int i = 0; i < nbNodes; i += iQ )
1550 sortedNodes.insert( fNodes[i] );
1551 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1552 first = (*(n++))->GetID();
1553 second.first = (*(n++))->GetID();
1554 second.second = (*(n++))->GetID();
1559 //=======================================================================
1560 //function : SplitVolumesIntoTetra
1561 //purpose : Split volumic elements into tetrahedra.
1562 //=======================================================================
1564 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1565 const int theMethodFlags)
1567 // std-like iterator on coordinates of nodes of mesh element
1568 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1569 NXyzIterator xyzEnd;
1571 SMDS_VolumeTool volTool;
1572 SMESH_MesherHelper helper( *GetMesh());
1574 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1575 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1577 SMESH_SequenceOfElemPtr newNodes, newElems;
1579 // map face of volume to it's baricenrtic node
1580 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1583 TIDSortedElemSet::const_iterator elem = theElems.begin();
1584 for ( ; elem != theElems.end(); ++elem )
1586 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1587 if ( geomType <= SMDSEntity_Quad_Tetra )
1588 continue; // tetra or face or ...
1590 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1592 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1593 if ( splitMethod._nbTetra < 1 ) continue;
1595 // find submesh to add new tetras to
1596 if ( !subMesh || !subMesh->Contains( *elem ))
1598 int shapeID = FindShape( *elem );
1599 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1600 subMesh = GetMeshDS()->MeshElements( shapeID );
1603 if ( (*elem)->IsQuadratic() )
1606 // add quadratic links to the helper
1607 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1609 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1610 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1611 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1613 helper.SetIsQuadratic( true );
1618 helper.SetIsQuadratic( false );
1620 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1621 if ( splitMethod._baryNode )
1623 // make a node at barycenter
1624 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1625 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1626 nodes.push_back( gcNode );
1627 newNodes.Append( gcNode );
1629 if ( !splitMethod._faceBaryNode.empty() )
1631 // make or find baricentric nodes of faces
1632 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1633 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1635 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1636 volFace2BaryNode.insert
1637 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1640 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1641 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1643 nodes.push_back( iF_n->second = f_n->second );
1648 helper.SetElementsOnShape( true );
1649 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1650 const int* tetConn = splitMethod._connectivity;
1651 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1652 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1653 nodes[ tetConn[1] ],
1654 nodes[ tetConn[2] ],
1655 nodes[ tetConn[3] ]));
1657 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1659 // Split faces on sides of the split volume
1661 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1662 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1664 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1665 if ( nbNodes < 4 ) continue;
1667 // find an existing face
1668 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1669 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1670 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1673 helper.SetElementsOnShape( false );
1674 vector< const SMDS_MeshElement* > triangles;
1676 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1677 if ( iF_n != splitMethod._faceBaryNode.end() )
1679 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1681 const SMDS_MeshNode* n1 = fNodes[iN];
1682 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1683 const SMDS_MeshNode *n3 = iF_n->second;
1684 if ( !volTool.IsFaceExternal( iF ))
1686 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1691 // among possible triangles create ones discribed by split method
1692 const int* nInd = volTool.GetFaceNodesIndices( iF );
1693 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1694 int iCom = 0; // common node of triangle faces to split into
1695 list< TTriangleFacet > facets;
1696 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1698 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1699 nInd[ iQ * ( (iCom+1)%nbNodes )],
1700 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1701 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1702 nInd[ iQ * ( (iCom+2)%nbNodes )],
1703 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1704 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1706 facets.push_back( t012 );
1707 facets.push_back( t023 );
1708 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1709 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1710 nInd[ iQ * ((iLast-1)%nbNodes )],
1711 nInd[ iQ * ((iLast )%nbNodes )]));
1715 list< TTriangleFacet >::iterator facet = facets.begin();
1716 for ( ; facet != facets.end(); ++facet )
1718 if ( !volTool.IsFaceExternal( iF ))
1719 swap( facet->_n2, facet->_n3 );
1720 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1721 volNodes[ facet->_n2 ],
1722 volNodes[ facet->_n3 ]));
1725 // find submesh to add new triangles in
1726 if ( !fSubMesh || !fSubMesh->Contains( face ))
1728 int shapeID = FindShape( face );
1729 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1731 for ( int i = 0; i < triangles.size(); ++i )
1733 if ( !triangles[i] ) continue;
1735 fSubMesh->AddElement( triangles[i]);
1736 newElems.Append( triangles[i] );
1738 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1739 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1742 } // loop on volume faces to split them into triangles
1744 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1746 } // loop on volumes to split
1748 myLastCreatedNodes = newNodes;
1749 myLastCreatedElems = newElems;
1752 //=======================================================================
1753 //function : AddToSameGroups
1754 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1755 //=======================================================================
1757 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1758 const SMDS_MeshElement* elemInGroups,
1759 SMESHDS_Mesh * aMesh)
1761 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1762 if (!groups.empty()) {
1763 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1764 for ( ; grIt != groups.end(); grIt++ ) {
1765 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1766 if ( group && group->Contains( elemInGroups ))
1767 group->SMDSGroup().Add( elemToAdd );
1773 //=======================================================================
1774 //function : RemoveElemFromGroups
1775 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1776 //=======================================================================
1777 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1778 SMESHDS_Mesh * aMesh)
1780 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1781 if (!groups.empty())
1783 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1784 for (; GrIt != groups.end(); GrIt++)
1786 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1787 if (!grp || grp->IsEmpty()) continue;
1788 grp->SMDSGroup().Remove(removeelem);
1793 //================================================================================
1795 * \brief Replace elemToRm by elemToAdd in the all groups
1797 //================================================================================
1799 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1800 const SMDS_MeshElement* elemToAdd,
1801 SMESHDS_Mesh * aMesh)
1803 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1804 if (!groups.empty()) {
1805 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1806 for ( ; grIt != groups.end(); grIt++ ) {
1807 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1808 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1809 group->SMDSGroup().Add( elemToAdd );
1814 //================================================================================
1816 * \brief Replace elemToRm by elemToAdd in the all groups
1818 //================================================================================
1820 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1821 const vector<const SMDS_MeshElement*>& elemToAdd,
1822 SMESHDS_Mesh * aMesh)
1824 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1825 if (!groups.empty())
1827 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1828 for ( ; grIt != groups.end(); grIt++ ) {
1829 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1830 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1831 for ( int i = 0; i < elemToAdd.size(); ++i )
1832 group->SMDSGroup().Add( elemToAdd[ i ] );
1837 //=======================================================================
1838 //function : QuadToTri
1839 //purpose : Cut quadrangles into triangles.
1840 // theCrit is used to select a diagonal to cut
1841 //=======================================================================
1843 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1844 const bool the13Diag)
1846 myLastCreatedElems.Clear();
1847 myLastCreatedNodes.Clear();
1849 MESSAGE( "::QuadToTri()" );
1851 SMESHDS_Mesh * aMesh = GetMeshDS();
1853 Handle(Geom_Surface) surface;
1854 SMESH_MesherHelper helper( *GetMesh() );
1856 TIDSortedElemSet::iterator itElem;
1857 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1858 const SMDS_MeshElement* elem = *itElem;
1859 if ( !elem || elem->GetType() != SMDSAbs_Face )
1861 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1862 if(!isquad) continue;
1864 if(elem->NbNodes()==4) {
1865 // retrieve element nodes
1866 const SMDS_MeshNode* aNodes [4];
1867 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1869 while ( itN->more() )
1870 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1872 int aShapeId = FindShape( elem );
1873 const SMDS_MeshElement* newElem1 = 0;
1874 const SMDS_MeshElement* newElem2 = 0;
1876 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1877 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1880 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1881 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1883 myLastCreatedElems.Append(newElem1);
1884 myLastCreatedElems.Append(newElem2);
1885 // put a new triangle on the same shape and add to the same groups
1888 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1889 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1891 AddToSameGroups( newElem1, elem, aMesh );
1892 AddToSameGroups( newElem2, elem, aMesh );
1893 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1894 aMesh->RemoveElement( elem );
1897 // Quadratic quadrangle
1899 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1901 // get surface elem is on
1902 int aShapeId = FindShape( elem );
1903 if ( aShapeId != helper.GetSubShapeID() ) {
1907 shape = aMesh->IndexToShape( aShapeId );
1908 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1909 TopoDS_Face face = TopoDS::Face( shape );
1910 surface = BRep_Tool::Surface( face );
1911 if ( !surface.IsNull() )
1912 helper.SetSubShape( shape );
1916 const SMDS_MeshNode* aNodes [8];
1917 const SMDS_MeshNode* inFaceNode = 0;
1918 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1920 while ( itN->more() ) {
1921 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1922 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1923 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1925 inFaceNode = aNodes[ i-1 ];
1929 // find middle point for (0,1,2,3)
1930 // and create a node in this point;
1932 if ( surface.IsNull() ) {
1934 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1938 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1941 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1943 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1945 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1946 myLastCreatedNodes.Append(newN);
1948 // create a new element
1949 const SMDS_MeshElement* newElem1 = 0;
1950 const SMDS_MeshElement* newElem2 = 0;
1951 const SMDS_MeshNode* N[6];
1959 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1960 aNodes[6], aNodes[7], newN );
1961 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1962 newN, aNodes[4], aNodes[5] );
1971 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1972 aNodes[7], aNodes[4], newN );
1973 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1974 newN, aNodes[5], aNodes[6] );
1976 myLastCreatedElems.Append(newElem1);
1977 myLastCreatedElems.Append(newElem2);
1978 // put a new triangle on the same shape and add to the same groups
1981 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1982 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1984 AddToSameGroups( newElem1, elem, aMesh );
1985 AddToSameGroups( newElem2, elem, aMesh );
1986 aMesh->RemoveElement( elem );
1993 //=======================================================================
1994 //function : getAngle
1996 //=======================================================================
1998 double getAngle(const SMDS_MeshElement * tr1,
1999 const SMDS_MeshElement * tr2,
2000 const SMDS_MeshNode * n1,
2001 const SMDS_MeshNode * n2)
2003 double angle = 2*PI; // bad angle
2006 SMESH::Controls::TSequenceOfXYZ P1, P2;
2007 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2008 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2011 if(!tr1->IsQuadratic())
2012 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2014 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2015 if ( N1.SquareMagnitude() <= gp::Resolution() )
2017 if(!tr2->IsQuadratic())
2018 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2020 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2021 if ( N2.SquareMagnitude() <= gp::Resolution() )
2024 // find the first diagonal node n1 in the triangles:
2025 // take in account a diagonal link orientation
2026 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2027 for ( int t = 0; t < 2; t++ ) {
2028 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2029 int i = 0, iDiag = -1;
2030 while ( it->more()) {
2031 const SMDS_MeshElement *n = it->next();
2032 if ( n == n1 || n == n2 ) {
2036 if ( i - iDiag == 1 )
2037 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2046 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2049 angle = N1.Angle( N2 );
2054 // =================================================
2055 // class generating a unique ID for a pair of nodes
2056 // and able to return nodes by that ID
2057 // =================================================
2061 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2062 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2065 long GetLinkID (const SMDS_MeshNode * n1,
2066 const SMDS_MeshNode * n2) const
2068 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2071 bool GetNodes (const long theLinkID,
2072 const SMDS_MeshNode* & theNode1,
2073 const SMDS_MeshNode* & theNode2) const
2075 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2076 if ( !theNode1 ) return false;
2077 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2078 if ( !theNode2 ) return false;
2084 const SMESHDS_Mesh* myMesh;
2089 //=======================================================================
2090 //function : TriToQuad
2091 //purpose : Fuse neighbour triangles into quadrangles.
2092 // theCrit is used to select a neighbour to fuse with.
2093 // theMaxAngle is a max angle between element normals at which
2094 // fusion is still performed.
2095 //=======================================================================
2097 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2098 SMESH::Controls::NumericalFunctorPtr theCrit,
2099 const double theMaxAngle)
2101 myLastCreatedElems.Clear();
2102 myLastCreatedNodes.Clear();
2104 MESSAGE( "::TriToQuad()" );
2106 if ( !theCrit.get() )
2109 SMESHDS_Mesh * aMesh = GetMeshDS();
2111 // Prepare data for algo: build
2112 // 1. map of elements with their linkIDs
2113 // 2. map of linkIDs with their elements
2115 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2116 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2117 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2118 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2120 TIDSortedElemSet::iterator itElem;
2121 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2122 const SMDS_MeshElement* elem = *itElem;
2123 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2124 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2125 if(!IsTria) continue;
2127 // retrieve element nodes
2128 const SMDS_MeshNode* aNodes [4];
2129 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2132 aNodes[ i++ ] = cast2Node( itN->next() );
2133 aNodes[ 3 ] = aNodes[ 0 ];
2136 for ( i = 0; i < 3; i++ ) {
2137 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2138 // check if elements sharing a link can be fused
2139 itLE = mapLi_listEl.find( link );
2140 if ( itLE != mapLi_listEl.end() ) {
2141 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2143 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2144 //if ( FindShape( elem ) != FindShape( elem2 ))
2145 // continue; // do not fuse triangles laying on different shapes
2146 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2147 continue; // avoid making badly shaped quads
2148 (*itLE).second.push_back( elem );
2151 mapLi_listEl[ link ].push_back( elem );
2153 mapEl_setLi [ elem ].insert( link );
2156 // Clean the maps from the links shared by a sole element, ie
2157 // links to which only one element is bound in mapLi_listEl
2159 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2160 int nbElems = (*itLE).second.size();
2161 if ( nbElems < 2 ) {
2162 const SMDS_MeshElement* elem = (*itLE).second.front();
2163 SMESH_TLink link = (*itLE).first;
2164 mapEl_setLi[ elem ].erase( link );
2165 if ( mapEl_setLi[ elem ].empty() )
2166 mapEl_setLi.erase( elem );
2170 // Algo: fuse triangles into quadrangles
2172 while ( ! mapEl_setLi.empty() ) {
2173 // Look for the start element:
2174 // the element having the least nb of shared links
2175 const SMDS_MeshElement* startElem = 0;
2177 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2178 int nbLinks = (*itEL).second.size();
2179 if ( nbLinks < minNbLinks ) {
2180 startElem = (*itEL).first;
2181 minNbLinks = nbLinks;
2182 if ( minNbLinks == 1 )
2187 // search elements to fuse starting from startElem or links of elements
2188 // fused earlyer - startLinks
2189 list< SMESH_TLink > startLinks;
2190 while ( startElem || !startLinks.empty() ) {
2191 while ( !startElem && !startLinks.empty() ) {
2192 // Get an element to start, by a link
2193 SMESH_TLink linkId = startLinks.front();
2194 startLinks.pop_front();
2195 itLE = mapLi_listEl.find( linkId );
2196 if ( itLE != mapLi_listEl.end() ) {
2197 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2198 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2199 for ( ; itE != listElem.end() ; itE++ )
2200 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2202 mapLi_listEl.erase( itLE );
2207 // Get candidates to be fused
2208 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2209 const SMESH_TLink *link12, *link13;
2211 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2212 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2213 ASSERT( !setLi.empty() );
2214 set< SMESH_TLink >::iterator itLi;
2215 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2217 const SMESH_TLink & link = (*itLi);
2218 itLE = mapLi_listEl.find( link );
2219 if ( itLE == mapLi_listEl.end() )
2222 const SMDS_MeshElement* elem = (*itLE).second.front();
2224 elem = (*itLE).second.back();
2225 mapLi_listEl.erase( itLE );
2226 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2237 // add other links of elem to list of links to re-start from
2238 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2239 set< SMESH_TLink >::iterator it;
2240 for ( it = links.begin(); it != links.end(); it++ ) {
2241 const SMESH_TLink& link2 = (*it);
2242 if ( link2 != link )
2243 startLinks.push_back( link2 );
2247 // Get nodes of possible quadrangles
2248 const SMDS_MeshNode *n12 [4], *n13 [4];
2249 bool Ok12 = false, Ok13 = false;
2250 const SMDS_MeshNode *linkNode1, *linkNode2;
2252 linkNode1 = link12->first;
2253 linkNode2 = link12->second;
2254 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2258 linkNode1 = link13->first;
2259 linkNode2 = link13->second;
2260 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2264 // Choose a pair to fuse
2265 if ( Ok12 && Ok13 ) {
2266 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2267 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2268 double aBadRate12 = getBadRate( &quad12, theCrit );
2269 double aBadRate13 = getBadRate( &quad13, theCrit );
2270 if ( aBadRate13 < aBadRate12 )
2277 // and remove fused elems and removed links from the maps
2278 mapEl_setLi.erase( tr1 );
2280 mapEl_setLi.erase( tr2 );
2281 mapLi_listEl.erase( *link12 );
2282 if(tr1->NbNodes()==3) {
2283 const SMDS_MeshElement* newElem = 0;
2284 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2285 myLastCreatedElems.Append(newElem);
2286 AddToSameGroups( newElem, tr1, aMesh );
2287 int aShapeId = tr1->getshapeId();
2290 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2292 aMesh->RemoveElement( tr1 );
2293 aMesh->RemoveElement( tr2 );
2296 const SMDS_MeshNode* N1 [6];
2297 const SMDS_MeshNode* N2 [6];
2298 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2299 // now we receive following N1 and N2 (using numeration as above image)
2300 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2301 // i.e. first nodes from both arrays determ new diagonal
2302 const SMDS_MeshNode* aNodes[8];
2311 const SMDS_MeshElement* newElem = 0;
2312 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2313 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2314 myLastCreatedElems.Append(newElem);
2315 AddToSameGroups( newElem, tr1, aMesh );
2316 int aShapeId = tr1->getshapeId();
2319 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2321 aMesh->RemoveElement( tr1 );
2322 aMesh->RemoveElement( tr2 );
2323 // remove middle node (9)
2324 GetMeshDS()->RemoveNode( N1[4] );
2328 mapEl_setLi.erase( tr3 );
2329 mapLi_listEl.erase( *link13 );
2330 if(tr1->NbNodes()==3) {
2331 const SMDS_MeshElement* newElem = 0;
2332 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2333 myLastCreatedElems.Append(newElem);
2334 AddToSameGroups( newElem, tr1, aMesh );
2335 int aShapeId = tr1->getshapeId();
2338 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2340 aMesh->RemoveElement( tr1 );
2341 aMesh->RemoveElement( tr3 );
2344 const SMDS_MeshNode* N1 [6];
2345 const SMDS_MeshNode* N2 [6];
2346 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2347 // now we receive following N1 and N2 (using numeration as above image)
2348 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2349 // i.e. first nodes from both arrays determ new diagonal
2350 const SMDS_MeshNode* aNodes[8];
2359 const SMDS_MeshElement* newElem = 0;
2360 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2361 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2362 myLastCreatedElems.Append(newElem);
2363 AddToSameGroups( newElem, tr1, aMesh );
2364 int aShapeId = tr1->getshapeId();
2367 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2369 aMesh->RemoveElement( tr1 );
2370 aMesh->RemoveElement( tr3 );
2371 // remove middle node (9)
2372 GetMeshDS()->RemoveNode( N1[4] );
2376 // Next element to fuse: the rejected one
2378 startElem = Ok12 ? tr3 : tr2;
2380 } // if ( startElem )
2381 } // while ( startElem || !startLinks.empty() )
2382 } // while ( ! mapEl_setLi.empty() )
2388 /*#define DUMPSO(txt) \
2389 // cout << txt << endl;
2390 //=============================================================================
2394 //=============================================================================
2395 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2399 int tmp = idNodes[ i1 ];
2400 idNodes[ i1 ] = idNodes[ i2 ];
2401 idNodes[ i2 ] = tmp;
2402 gp_Pnt Ptmp = P[ i1 ];
2405 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2408 //=======================================================================
2409 //function : SortQuadNodes
2410 //purpose : Set 4 nodes of a quadrangle face in a good order.
2411 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2413 //=======================================================================
2415 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2420 for ( i = 0; i < 4; i++ ) {
2421 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2423 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2426 gp_Vec V1(P[0], P[1]);
2427 gp_Vec V2(P[0], P[2]);
2428 gp_Vec V3(P[0], P[3]);
2430 gp_Vec Cross1 = V1 ^ V2;
2431 gp_Vec Cross2 = V2 ^ V3;
2434 if (Cross1.Dot(Cross2) < 0)
2439 if (Cross1.Dot(Cross2) < 0)
2443 swap ( i, i + 1, idNodes, P );
2445 // for ( int ii = 0; ii < 4; ii++ ) {
2446 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2447 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2453 //=======================================================================
2454 //function : SortHexaNodes
2455 //purpose : Set 8 nodes of a hexahedron in a good order.
2456 // Return success status
2457 //=======================================================================
2459 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2464 DUMPSO( "INPUT: ========================================");
2465 for ( i = 0; i < 8; i++ ) {
2466 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2467 if ( !n ) return false;
2468 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2469 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2471 DUMPSO( "========================================");
2474 set<int> faceNodes; // ids of bottom face nodes, to be found
2475 set<int> checkedId1; // ids of tried 2-nd nodes
2476 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2477 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2478 int iMin, iLoop1 = 0;
2480 // Loop to try the 2-nd nodes
2482 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2484 // Find not checked 2-nd node
2485 for ( i = 1; i < 8; i++ )
2486 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2487 int id1 = idNodes[i];
2488 swap ( 1, i, idNodes, P );
2489 checkedId1.insert ( id1 );
2493 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2494 // ie that all but meybe one (id3 which is on the same face) nodes
2495 // lay on the same side from the triangle plane.
2497 bool manyInPlane = false; // more than 4 nodes lay in plane
2499 while ( ++iLoop2 < 6 ) {
2501 // get 1-2-3 plane coeffs
2502 Standard_Real A, B, C, D;
2503 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2504 if ( N.SquareMagnitude() > gp::Resolution() )
2506 gp_Pln pln ( P[0], N );
2507 pln.Coefficients( A, B, C, D );
2509 // find the node (iMin) closest to pln
2510 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2512 for ( i = 3; i < 8; i++ ) {
2513 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2514 if ( fabs( dist[i] ) < minDist ) {
2515 minDist = fabs( dist[i] );
2518 if ( fabs( dist[i] ) <= tol )
2519 idInPln.insert( idNodes[i] );
2522 // there should not be more than 4 nodes in bottom plane
2523 if ( idInPln.size() > 1 )
2525 DUMPSO( "### idInPln.size() = " << idInPln.size());
2526 // idInPlane does not contain the first 3 nodes
2527 if ( manyInPlane || idInPln.size() == 5)
2528 return false; // all nodes in one plane
2531 // set the 1-st node to be not in plane
2532 for ( i = 3; i < 8; i++ ) {
2533 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2534 DUMPSO( "### Reset 0-th node");
2535 swap( 0, i, idNodes, P );
2540 // reset to re-check second nodes
2541 leastDist = DBL_MAX;
2545 break; // from iLoop2;
2548 // check that the other 4 nodes are on the same side
2549 bool sameSide = true;
2550 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2551 for ( i = 3; sameSide && i < 8; i++ ) {
2553 sameSide = ( isNeg == dist[i] <= 0.);
2556 // keep best solution
2557 if ( sameSide && minDist < leastDist ) {
2558 leastDist = minDist;
2560 faceNodes.insert( idNodes[ 1 ] );
2561 faceNodes.insert( idNodes[ 2 ] );
2562 faceNodes.insert( idNodes[ iMin ] );
2563 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2564 << " leastDist = " << leastDist);
2565 if ( leastDist <= DBL_MIN )
2570 // set next 3-d node to check
2571 int iNext = 2 + iLoop2;
2573 DUMPSO( "Try 2-nd");
2574 swap ( 2, iNext, idNodes, P );
2576 } // while ( iLoop2 < 6 )
2579 if ( faceNodes.empty() ) return false;
2581 // Put the faceNodes in proper places
2582 for ( i = 4; i < 8; i++ ) {
2583 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2584 // find a place to put
2586 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2588 DUMPSO( "Set faceNodes");
2589 swap ( iTo, i, idNodes, P );
2594 // Set nodes of the found bottom face in good order
2595 DUMPSO( " Found bottom face: ");
2596 i = SortQuadNodes( theMesh, idNodes );
2598 gp_Pnt Ptmp = P[ i ];
2603 // for ( int ii = 0; ii < 4; ii++ ) {
2604 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2605 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2608 // Gravity center of the top and bottom faces
2609 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2610 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2612 // Get direction from the bottom to the top face
2613 gp_Vec upDir ( aGCb, aGCt );
2614 Standard_Real upDirSize = upDir.Magnitude();
2615 if ( upDirSize <= gp::Resolution() ) return false;
2618 // Assure that the bottom face normal points up
2619 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2620 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2621 if ( Nb.Dot( upDir ) < 0 ) {
2622 DUMPSO( "Reverse bottom face");
2623 swap( 1, 3, idNodes, P );
2626 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2627 Standard_Real minDist = DBL_MAX;
2628 for ( i = 4; i < 8; i++ ) {
2629 // projection of P[i] to the plane defined by P[0] and upDir
2630 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2631 Standard_Real sqDist = P[0].SquareDistance( Pp );
2632 if ( sqDist < minDist ) {
2637 DUMPSO( "Set 4-th");
2638 swap ( 4, iMin, idNodes, P );
2640 // Set nodes of the top face in good order
2641 DUMPSO( "Sort top face");
2642 i = SortQuadNodes( theMesh, &idNodes[4] );
2645 gp_Pnt Ptmp = P[ i ];
2650 // Assure that direction of the top face normal is from the bottom face
2651 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2652 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2653 if ( Nt.Dot( upDir ) < 0 ) {
2654 DUMPSO( "Reverse top face");
2655 swap( 5, 7, idNodes, P );
2658 // DUMPSO( "OUTPUT: ========================================");
2659 // for ( i = 0; i < 8; i++ ) {
2660 // float *p = ugrid->GetPoint(idNodes[i]);
2661 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2667 //================================================================================
2669 * \brief Return nodes linked to the given one
2670 * \param theNode - the node
2671 * \param linkedNodes - the found nodes
2672 * \param type - the type of elements to check
2674 * Medium nodes are ignored
2676 //================================================================================
2678 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2679 TIDSortedElemSet & linkedNodes,
2680 SMDSAbs_ElementType type )
2682 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2683 while ( elemIt->more() )
2685 const SMDS_MeshElement* elem = elemIt->next();
2686 if(elem->GetType() == SMDSAbs_0DElement)
2689 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2690 if ( elem->GetType() == SMDSAbs_Volume )
2692 SMDS_VolumeTool vol( elem );
2693 while ( nodeIt->more() ) {
2694 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2695 if ( theNode != n && vol.IsLinked( theNode, n ))
2696 linkedNodes.insert( n );
2701 for ( int i = 0; nodeIt->more(); ++i ) {
2702 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2703 if ( n == theNode ) {
2704 int iBefore = i - 1;
2706 if ( elem->IsQuadratic() ) {
2707 int nb = elem->NbNodes() / 2;
2708 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2709 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2711 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2712 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2719 //=======================================================================
2720 //function : laplacianSmooth
2721 //purpose : pulls theNode toward the center of surrounding nodes directly
2722 // connected to that node along an element edge
2723 //=======================================================================
2725 void laplacianSmooth(const SMDS_MeshNode* theNode,
2726 const Handle(Geom_Surface)& theSurface,
2727 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2729 // find surrounding nodes
2731 TIDSortedElemSet nodeSet;
2732 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2734 // compute new coodrs
2736 double coord[] = { 0., 0., 0. };
2737 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2738 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2739 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2740 if ( theSurface.IsNull() ) { // smooth in 3D
2741 coord[0] += node->X();
2742 coord[1] += node->Y();
2743 coord[2] += node->Z();
2745 else { // smooth in 2D
2746 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2747 gp_XY* uv = theUVMap[ node ];
2748 coord[0] += uv->X();
2749 coord[1] += uv->Y();
2752 int nbNodes = nodeSet.size();
2755 coord[0] /= nbNodes;
2756 coord[1] /= nbNodes;
2758 if ( !theSurface.IsNull() ) {
2759 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2760 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2761 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2767 coord[2] /= nbNodes;
2771 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2774 //=======================================================================
2775 //function : centroidalSmooth
2776 //purpose : pulls theNode toward the element-area-weighted centroid of the
2777 // surrounding elements
2778 //=======================================================================
2780 void centroidalSmooth(const SMDS_MeshNode* theNode,
2781 const Handle(Geom_Surface)& theSurface,
2782 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2784 gp_XYZ aNewXYZ(0.,0.,0.);
2785 SMESH::Controls::Area anAreaFunc;
2786 double totalArea = 0.;
2791 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2792 while ( elemIt->more() )
2794 const SMDS_MeshElement* elem = elemIt->next();
2797 gp_XYZ elemCenter(0.,0.,0.);
2798 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2799 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2800 int nn = elem->NbNodes();
2801 if(elem->IsQuadratic()) nn = nn/2;
2803 //while ( itN->more() ) {
2805 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2807 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2808 aNodePoints.push_back( aP );
2809 if ( !theSurface.IsNull() ) { // smooth in 2D
2810 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2811 gp_XY* uv = theUVMap[ aNode ];
2812 aP.SetCoord( uv->X(), uv->Y(), 0. );
2816 double elemArea = anAreaFunc.GetValue( aNodePoints );
2817 totalArea += elemArea;
2819 aNewXYZ += elemCenter * elemArea;
2821 aNewXYZ /= totalArea;
2822 if ( !theSurface.IsNull() ) {
2823 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2824 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2829 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2832 //=======================================================================
2833 //function : getClosestUV
2834 //purpose : return UV of closest projection
2835 //=======================================================================
2837 static bool getClosestUV (Extrema_GenExtPS& projector,
2838 const gp_Pnt& point,
2841 projector.Perform( point );
2842 if ( projector.IsDone() ) {
2843 double u, v, minVal = DBL_MAX;
2844 for ( int i = projector.NbExt(); i > 0; i-- )
2845 if ( projector.Value( i ) < minVal ) {
2846 minVal = projector.Value( i );
2847 projector.Point( i ).Parameter( u, v );
2849 result.SetCoord( u, v );
2855 //=======================================================================
2857 //purpose : Smooth theElements during theNbIterations or until a worst
2858 // element has aspect ratio <= theTgtAspectRatio.
2859 // Aspect Ratio varies in range [1.0, inf].
2860 // If theElements is empty, the whole mesh is smoothed.
2861 // theFixedNodes contains additionally fixed nodes. Nodes built
2862 // on edges and boundary nodes are always fixed.
2863 //=======================================================================
2865 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2866 set<const SMDS_MeshNode*> & theFixedNodes,
2867 const SmoothMethod theSmoothMethod,
2868 const int theNbIterations,
2869 double theTgtAspectRatio,
2872 myLastCreatedElems.Clear();
2873 myLastCreatedNodes.Clear();
2875 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2877 if ( theTgtAspectRatio < 1.0 )
2878 theTgtAspectRatio = 1.0;
2880 const double disttol = 1.e-16;
2882 SMESH::Controls::AspectRatio aQualityFunc;
2884 SMESHDS_Mesh* aMesh = GetMeshDS();
2886 if ( theElems.empty() ) {
2887 // add all faces to theElems
2888 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2889 while ( fIt->more() ) {
2890 const SMDS_MeshElement* face = fIt->next();
2891 theElems.insert( face );
2894 // get all face ids theElems are on
2895 set< int > faceIdSet;
2896 TIDSortedElemSet::iterator itElem;
2898 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2899 int fId = FindShape( *itElem );
2900 // check that corresponding submesh exists and a shape is face
2902 faceIdSet.find( fId ) == faceIdSet.end() &&
2903 aMesh->MeshElements( fId )) {
2904 TopoDS_Shape F = aMesh->IndexToShape( fId );
2905 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2906 faceIdSet.insert( fId );
2909 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2911 // ===============================================
2912 // smooth elements on each TopoDS_Face separately
2913 // ===============================================
2915 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2916 for ( ; fId != faceIdSet.rend(); ++fId ) {
2917 // get face surface and submesh
2918 Handle(Geom_Surface) surface;
2919 SMESHDS_SubMesh* faceSubMesh = 0;
2921 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2922 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2923 bool isUPeriodic = false, isVPeriodic = false;
2925 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2926 surface = BRep_Tool::Surface( face );
2927 faceSubMesh = aMesh->MeshElements( *fId );
2928 fToler2 = BRep_Tool::Tolerance( face );
2929 fToler2 *= fToler2 * 10.;
2930 isUPeriodic = surface->IsUPeriodic();
2932 vPeriod = surface->UPeriod();
2933 isVPeriodic = surface->IsVPeriodic();
2935 uPeriod = surface->VPeriod();
2936 surface->Bounds( u1, u2, v1, v2 );
2938 // ---------------------------------------------------------
2939 // for elements on a face, find movable and fixed nodes and
2940 // compute UV for them
2941 // ---------------------------------------------------------
2942 bool checkBoundaryNodes = false;
2943 bool isQuadratic = false;
2944 set<const SMDS_MeshNode*> setMovableNodes;
2945 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2946 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2947 list< const SMDS_MeshElement* > elemsOnFace;
2949 Extrema_GenExtPS projector;
2950 GeomAdaptor_Surface surfAdaptor;
2951 if ( !surface.IsNull() ) {
2952 surfAdaptor.Load( surface );
2953 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2955 int nbElemOnFace = 0;
2956 itElem = theElems.begin();
2957 // loop on not yet smoothed elements: look for elems on a face
2958 while ( itElem != theElems.end() ) {
2959 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2960 break; // all elements found
2962 const SMDS_MeshElement* elem = *itElem;
2963 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2964 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2968 elemsOnFace.push_back( elem );
2969 theElems.erase( itElem++ );
2973 isQuadratic = elem->IsQuadratic();
2975 // get movable nodes of elem
2976 const SMDS_MeshNode* node;
2977 SMDS_TypeOfPosition posType;
2978 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2979 int nn = 0, nbn = elem->NbNodes();
2980 if(elem->IsQuadratic())
2982 while ( nn++ < nbn ) {
2983 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2984 const SMDS_PositionPtr& pos = node->GetPosition();
2985 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2986 if (posType != SMDS_TOP_EDGE &&
2987 posType != SMDS_TOP_VERTEX &&
2988 theFixedNodes.find( node ) == theFixedNodes.end())
2990 // check if all faces around the node are on faceSubMesh
2991 // because a node on edge may be bound to face
2992 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2994 if ( faceSubMesh ) {
2995 while ( eIt->more() && all ) {
2996 const SMDS_MeshElement* e = eIt->next();
2997 all = faceSubMesh->Contains( e );
3001 setMovableNodes.insert( node );
3003 checkBoundaryNodes = true;
3005 if ( posType == SMDS_TOP_3DSPACE )
3006 checkBoundaryNodes = true;
3009 if ( surface.IsNull() )
3012 // get nodes to check UV
3013 list< const SMDS_MeshNode* > uvCheckNodes;
3014 itN = elem->nodesIterator();
3015 nn = 0; nbn = elem->NbNodes();
3016 if(elem->IsQuadratic())
3018 while ( nn++ < nbn ) {
3019 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3020 if ( uvMap.find( node ) == uvMap.end() )
3021 uvCheckNodes.push_back( node );
3022 // add nodes of elems sharing node
3023 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3024 // while ( eIt->more() ) {
3025 // const SMDS_MeshElement* e = eIt->next();
3026 // if ( e != elem ) {
3027 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3028 // while ( nIt->more() ) {
3029 // const SMDS_MeshNode* n =
3030 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3031 // if ( uvMap.find( n ) == uvMap.end() )
3032 // uvCheckNodes.push_back( n );
3038 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3039 for ( ; n != uvCheckNodes.end(); ++n ) {
3042 const SMDS_PositionPtr& pos = node->GetPosition();
3043 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3045 switch ( posType ) {
3046 case SMDS_TOP_FACE: {
3047 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3048 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3051 case SMDS_TOP_EDGE: {
3052 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3053 Handle(Geom2d_Curve) pcurve;
3054 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3055 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3056 if ( !pcurve.IsNull() ) {
3057 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3058 uv = pcurve->Value( u ).XY();
3062 case SMDS_TOP_VERTEX: {
3063 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3064 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3065 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3070 // check existing UV
3071 bool project = true;
3072 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3073 double dist1 = DBL_MAX, dist2 = 0;
3074 if ( posType != SMDS_TOP_3DSPACE ) {
3075 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3076 project = dist1 > fToler2;
3078 if ( project ) { // compute new UV
3080 if ( !getClosestUV( projector, pNode, newUV )) {
3081 MESSAGE("Node Projection Failed " << node);
3085 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3087 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3089 if ( posType != SMDS_TOP_3DSPACE )
3090 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3091 if ( dist2 < dist1 )
3095 // store UV in the map
3096 listUV.push_back( uv );
3097 uvMap.insert( make_pair( node, &listUV.back() ));
3099 } // loop on not yet smoothed elements
3101 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3102 checkBoundaryNodes = true;
3104 // fix nodes on mesh boundary
3106 if ( checkBoundaryNodes ) {
3107 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3108 map< NLink, int >::iterator link_nb;
3109 // put all elements links to linkNbMap
3110 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3111 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3112 const SMDS_MeshElement* elem = (*elemIt);
3113 int nbn = elem->NbNodes();
3114 if(elem->IsQuadratic())
3116 // loop on elem links: insert them in linkNbMap
3117 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3118 for ( int iN = 0; iN < nbn; ++iN ) {
3119 curNode = elem->GetNode( iN );
3121 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3122 else link = make_pair( prevNode , curNode );
3124 link_nb = linkNbMap.find( link );
3125 if ( link_nb == linkNbMap.end() )
3126 linkNbMap.insert( make_pair ( link, 1 ));
3131 // remove nodes that are in links encountered only once from setMovableNodes
3132 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3133 if ( link_nb->second == 1 ) {
3134 setMovableNodes.erase( link_nb->first.first );
3135 setMovableNodes.erase( link_nb->first.second );
3140 // -----------------------------------------------------
3141 // for nodes on seam edge, compute one more UV ( uvMap2 );
3142 // find movable nodes linked to nodes on seam and which
3143 // are to be smoothed using the second UV ( uvMap2 )
3144 // -----------------------------------------------------
3146 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3147 if ( !surface.IsNull() ) {
3148 TopExp_Explorer eExp( face, TopAbs_EDGE );
3149 for ( ; eExp.More(); eExp.Next() ) {
3150 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3151 if ( !BRep_Tool::IsClosed( edge, face ))
3153 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3154 if ( !sm ) continue;
3155 // find out which parameter varies for a node on seam
3158 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3159 if ( pcurve.IsNull() ) continue;
3160 uv1 = pcurve->Value( f );
3162 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3163 if ( pcurve.IsNull() ) continue;
3164 uv2 = pcurve->Value( f );
3165 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3167 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3168 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3170 // get nodes on seam and its vertices
3171 list< const SMDS_MeshNode* > seamNodes;
3172 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3173 while ( nSeamIt->more() ) {
3174 const SMDS_MeshNode* node = nSeamIt->next();
3175 if ( !isQuadratic || !IsMedium( node ))
3176 seamNodes.push_back( node );
3178 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3179 for ( ; vExp.More(); vExp.Next() ) {
3180 sm = aMesh->MeshElements( vExp.Current() );
3182 nSeamIt = sm->GetNodes();
3183 while ( nSeamIt->more() )
3184 seamNodes.push_back( nSeamIt->next() );
3187 // loop on nodes on seam
3188 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3189 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3190 const SMDS_MeshNode* nSeam = *noSeIt;
3191 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3192 if ( n_uv == uvMap.end() )
3195 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3196 // set the second UV
3197 listUV.push_back( *n_uv->second );
3198 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3199 if ( uvMap2.empty() )
3200 uvMap2 = uvMap; // copy the uvMap contents
3201 uvMap2[ nSeam ] = &listUV.back();
3203 // collect movable nodes linked to ones on seam in nodesNearSeam
3204 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3205 while ( eIt->more() ) {
3206 const SMDS_MeshElement* e = eIt->next();
3207 int nbUseMap1 = 0, nbUseMap2 = 0;
3208 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3209 int nn = 0, nbn = e->NbNodes();
3210 if(e->IsQuadratic()) nbn = nbn/2;
3211 while ( nn++ < nbn )
3213 const SMDS_MeshNode* n =
3214 static_cast<const SMDS_MeshNode*>( nIt->next() );
3216 setMovableNodes.find( n ) == setMovableNodes.end() )
3218 // add only nodes being closer to uv2 than to uv1
3219 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3220 0.5 * ( n->Y() + nSeam->Y() ),
3221 0.5 * ( n->Z() + nSeam->Z() ));
3223 getClosestUV( projector, pMid, uv );
3224 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3225 nodesNearSeam.insert( n );
3231 // for centroidalSmooth all element nodes must
3232 // be on one side of a seam
3233 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3234 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3236 while ( nn++ < nbn ) {
3237 const SMDS_MeshNode* n =
3238 static_cast<const SMDS_MeshNode*>( nIt->next() );
3239 setMovableNodes.erase( n );
3243 } // loop on nodes on seam
3244 } // loop on edge of a face
3245 } // if ( !face.IsNull() )
3247 if ( setMovableNodes.empty() ) {
3248 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3249 continue; // goto next face
3257 double maxRatio = -1., maxDisplacement = -1.;
3258 set<const SMDS_MeshNode*>::iterator nodeToMove;
3259 for ( it = 0; it < theNbIterations; it++ ) {
3260 maxDisplacement = 0.;
3261 nodeToMove = setMovableNodes.begin();
3262 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3263 const SMDS_MeshNode* node = (*nodeToMove);
3264 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3267 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3268 if ( theSmoothMethod == LAPLACIAN )
3269 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3271 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3273 // node displacement
3274 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3275 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3276 if ( aDispl > maxDisplacement )
3277 maxDisplacement = aDispl;
3279 // no node movement => exit
3280 //if ( maxDisplacement < 1.e-16 ) {
3281 if ( maxDisplacement < disttol ) {
3282 MESSAGE("-- no node movement --");
3286 // check elements quality
3288 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3289 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3290 const SMDS_MeshElement* elem = (*elemIt);
3291 if ( !elem || elem->GetType() != SMDSAbs_Face )
3293 SMESH::Controls::TSequenceOfXYZ aPoints;
3294 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3295 double aValue = aQualityFunc.GetValue( aPoints );
3296 if ( aValue > maxRatio )
3300 if ( maxRatio <= theTgtAspectRatio ) {
3301 MESSAGE("-- quality achived --");
3304 if (it+1 == theNbIterations) {
3305 MESSAGE("-- Iteration limit exceeded --");
3307 } // smoothing iterations
3309 MESSAGE(" Face id: " << *fId <<
3310 " Nb iterstions: " << it <<
3311 " Displacement: " << maxDisplacement <<
3312 " Aspect Ratio " << maxRatio);
3314 // ---------------------------------------
3315 // new nodes positions are computed,
3316 // record movement in DS and set new UV
3317 // ---------------------------------------
3318 nodeToMove = setMovableNodes.begin();
3319 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3320 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3321 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3322 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3323 if ( node_uv != uvMap.end() ) {
3324 gp_XY* uv = node_uv->second;
3326 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3330 // move medium nodes of quadratic elements
3333 SMESH_MesherHelper helper( *GetMesh() );
3334 if ( !face.IsNull() )
3335 helper.SetSubShape( face );
3336 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3337 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3338 const SMDS_VtkFace* QF =
3339 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3340 if(QF && QF->IsQuadratic()) {
3341 vector<const SMDS_MeshNode*> Ns;
3342 Ns.reserve(QF->NbNodes()+1);
3343 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3344 while ( anIter->more() )
3345 Ns.push_back( cast2Node(anIter->next()) );
3346 Ns.push_back( Ns[0] );
3348 for(int i=0; i<QF->NbNodes(); i=i+2) {
3349 if ( !surface.IsNull() ) {
3350 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3351 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3352 gp_XY uv = ( uv1 + uv2 ) / 2.;
3353 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3354 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3357 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3358 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3359 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3361 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3362 fabs( Ns[i+1]->Y() - y ) > disttol ||
3363 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3364 // we have to move i+1 node
3365 aMesh->MoveNode( Ns[i+1], x, y, z );
3372 } // loop on face ids
3376 //=======================================================================
3377 //function : isReverse
3378 //purpose : Return true if normal of prevNodes is not co-directied with
3379 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3380 // iNotSame is where prevNodes and nextNodes are different
3381 //=======================================================================
3383 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3384 vector<const SMDS_MeshNode*> nextNodes,
3388 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3389 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3391 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3392 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3393 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3394 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3396 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3397 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3398 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3399 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3401 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3403 return (vA ^ vB) * vN < 0.0;
3406 //=======================================================================
3408 * \brief Create elements by sweeping an element
3409 * \param elem - element to sweep
3410 * \param newNodesItVec - nodes generated from each node of the element
3411 * \param newElems - generated elements
3412 * \param nbSteps - number of sweeping steps
3413 * \param srcElements - to append elem for each generated element
3415 //=======================================================================
3417 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3418 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3419 list<const SMDS_MeshElement*>& newElems,
3421 SMESH_SequenceOfElemPtr& srcElements)
3423 //MESSAGE("sweepElement " << nbSteps);
3424 SMESHDS_Mesh* aMesh = GetMeshDS();
3426 // Loop on elem nodes:
3427 // find new nodes and detect same nodes indices
3428 int nbNodes = elem->NbNodes();
3429 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3430 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3431 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3432 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3434 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3435 vector<int> sames(nbNodes);
3436 vector<bool> issimple(nbNodes);
3438 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3439 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3440 const SMDS_MeshNode* node = nnIt->first;
3441 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3442 if ( listNewNodes.empty() ) {
3446 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3448 itNN[ iNode ] = listNewNodes.begin();
3449 prevNod[ iNode ] = node;
3450 nextNod[ iNode ] = listNewNodes.front();
3451 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3452 if ( prevNod[ iNode ] != nextNod [ iNode ])
3453 iNotSameNode = iNode;
3457 sames[nbSame++] = iNode;
3462 //cerr<<" nbSame = "<<nbSame<<endl;
3463 if ( nbSame == nbNodes || nbSame > 2) {
3464 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3465 //INFOS( " Too many same nodes of element " << elem->GetID() );
3469 // if( elem->IsQuadratic() && nbSame>0 ) {
3470 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3474 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3475 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3477 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3478 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3479 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3483 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3484 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3485 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3486 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3488 // check element orientation
3490 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3491 //MESSAGE("Reversed elem " << elem );
3495 std::swap( iBeforeSame, iAfterSame );
3498 // make new elements
3499 const SMDS_MeshElement* lastElem = elem;
3500 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3502 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3503 if(issimple[iNode]) {
3504 nextNod[ iNode ] = *itNN[ iNode ];
3508 if( elem->GetType()==SMDSAbs_Node ) {
3509 // we have to use two nodes
3510 midlNod[ iNode ] = *itNN[ iNode ];
3512 nextNod[ iNode ] = *itNN[ iNode ];
3515 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3516 // we have to use each second node
3518 nextNod[ iNode ] = *itNN[ iNode ];
3522 // we have to use two nodes
3523 midlNod[ iNode ] = *itNN[ iNode ];
3525 nextNod[ iNode ] = *itNN[ iNode ];
3530 SMDS_MeshElement* aNewElem = 0;
3531 if(!elem->IsPoly()) {
3532 switch ( nbNodes ) {
3536 if ( nbSame == 0 ) {
3538 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3540 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3546 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3547 nextNod[ 1 ], nextNod[ 0 ] );
3549 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3550 nextNod[ iNotSameNode ] );
3554 case 3: { // TRIANGLE or quadratic edge
3555 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3557 if ( nbSame == 0 ) // --- pentahedron
3558 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3559 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3561 else if ( nbSame == 1 ) // --- pyramid
3562 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3563 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3564 nextNod[ iSameNode ]);
3566 else // 2 same nodes: --- tetrahedron
3567 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3568 nextNod[ iNotSameNode ]);
3570 else { // quadratic edge
3571 if(nbSame==0) { // quadratic quadrangle
3572 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3573 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3575 else if(nbSame==1) { // quadratic triangle
3577 return; // medium node on axis
3579 else if(sames[0]==0) {
3580 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3581 nextNod[2], midlNod[1], prevNod[2]);
3583 else { // sames[0]==1
3584 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3585 midlNod[0], nextNod[2], prevNod[2]);
3594 case 4: { // QUADRANGLE
3596 if ( nbSame == 0 ) // --- hexahedron
3597 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3598 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3600 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3601 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3602 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3603 nextNod[ iSameNode ]);
3604 newElems.push_back( aNewElem );
3605 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3606 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3607 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3609 else if ( nbSame == 2 ) { // pentahedron
3610 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3611 // iBeforeSame is same too
3612 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3613 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3614 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3616 // iAfterSame is same too
3617 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3618 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3619 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3623 case 6: { // quadratic triangle
3624 // create pentahedron with 15 nodes
3626 if(i0>0) { // reversed case
3627 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3628 nextNod[0], nextNod[2], nextNod[1],
3629 prevNod[5], prevNod[4], prevNod[3],
3630 nextNod[5], nextNod[4], nextNod[3],
3631 midlNod[0], midlNod[2], midlNod[1]);
3633 else { // not reversed case
3634 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3635 nextNod[0], nextNod[1], nextNod[2],
3636 prevNod[3], prevNod[4], prevNod[5],
3637 nextNod[3], nextNod[4], nextNod[5],
3638 midlNod[0], midlNod[1], midlNod[2]);
3641 else if(nbSame==1) {
3642 // 2d order pyramid of 13 nodes
3643 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3644 // int n12,int n23,int n34,int n41,
3645 // int n15,int n25,int n35,int n45, int ID);
3647 int n1,n4,n41,n15,n45;
3648 if(i0>0) { // reversed case
3649 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3650 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3656 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3657 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3662 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3663 nextNod[n4], prevNod[n4], prevNod[n5],
3664 midlNod[n1], nextNod[n41],
3665 midlNod[n4], prevNod[n41],
3666 prevNod[n15], nextNod[n15],
3667 nextNod[n45], prevNod[n45]);
3669 else if(nbSame==2) {
3670 // 2d order tetrahedron of 10 nodes
3671 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3672 // int n12,int n23,int n31,
3673 // int n14,int n24,int n34, int ID);
3674 int n1 = iNotSameNode;
3675 int n2,n3,n12,n23,n31;
3676 if(i0>0) { // reversed case
3677 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3678 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3684 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3685 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3690 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3691 prevNod[n12], prevNod[n23], prevNod[n31],
3692 midlNod[n1], nextNod[n12], nextNod[n31]);
3696 case 8: { // quadratic quadrangle
3698 // create hexahedron with 20 nodes
3699 if(i0>0) { // reversed case
3700 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3701 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3702 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3703 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3704 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3706 else { // not reversed case
3707 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3708 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3709 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3710 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3711 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3714 else if(nbSame==1) {
3715 // --- pyramid + pentahedron - can not be created since it is needed
3716 // additional middle node ot the center of face
3717 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3720 else if(nbSame==2) {
3721 // 2d order Pentahedron with 15 nodes
3722 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3723 // int n12,int n23,int n31,int n45,int n56,int n64,
3724 // int n14,int n25,int n36, int ID);
3726 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3727 // iBeforeSame is same too
3734 // iAfterSame is same too
3740 int n12,n45,n14,n25;
3741 if(i0>0) { //reversed case
3753 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3754 prevNod[n4], prevNod[n5], nextNod[n5],
3755 prevNod[n12], midlNod[n2], nextNod[n12],
3756 prevNod[n45], midlNod[n5], nextNod[n45],
3757 prevNod[n14], prevNod[n25], nextNod[n25]);
3762 // realized for extrusion only
3763 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3764 //vector<int> quantities (nbNodes + 2);
3766 //quantities[0] = nbNodes; // bottom of prism
3767 //for (int inode = 0; inode < nbNodes; inode++) {
3768 // polyedre_nodes[inode] = prevNod[inode];
3771 //quantities[1] = nbNodes; // top of prism
3772 //for (int inode = 0; inode < nbNodes; inode++) {
3773 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3776 //for (int iface = 0; iface < nbNodes; iface++) {
3777 // quantities[iface + 2] = 4;
3778 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3779 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3780 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3781 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3782 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3784 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3791 // realized for extrusion only
3792 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3793 vector<int> quantities (nbNodes + 2);
3795 quantities[0] = nbNodes; // bottom of prism
3796 for (int inode = 0; inode < nbNodes; inode++) {
3797 polyedre_nodes[inode] = prevNod[inode];
3800 quantities[1] = nbNodes; // top of prism
3801 for (int inode = 0; inode < nbNodes; inode++) {
3802 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3805 for (int iface = 0; iface < nbNodes; iface++) {
3806 quantities[iface + 2] = 4;
3807 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3808 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3809 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3810 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3811 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3813 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3817 newElems.push_back( aNewElem );
3818 myLastCreatedElems.Append(aNewElem);
3819 srcElements.Append( elem );
3820 lastElem = aNewElem;
3823 // set new prev nodes
3824 for ( iNode = 0; iNode < nbNodes; iNode++ )
3825 prevNod[ iNode ] = nextNod[ iNode ];
3830 //=======================================================================
3832 * \brief Create 1D and 2D elements around swept elements
3833 * \param mapNewNodes - source nodes and ones generated from them
3834 * \param newElemsMap - source elements and ones generated from them
3835 * \param elemNewNodesMap - nodes generated from each node of each element
3836 * \param elemSet - all swept elements
3837 * \param nbSteps - number of sweeping steps
3838 * \param srcElements - to append elem for each generated element
3840 //=======================================================================
3842 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3843 TElemOfElemListMap & newElemsMap,
3844 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3845 TIDSortedElemSet& elemSet,
3847 SMESH_SequenceOfElemPtr& srcElements)
3849 MESSAGE("makeWalls");
3850 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3851 SMESHDS_Mesh* aMesh = GetMeshDS();
3853 // Find nodes belonging to only one initial element - sweep them to get edges.
3855 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3856 for ( ; nList != mapNewNodes.end(); nList++ ) {
3857 const SMDS_MeshNode* node =
3858 static_cast<const SMDS_MeshNode*>( nList->first );
3859 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3860 int nbInitElems = 0;
3861 const SMDS_MeshElement* el = 0;
3862 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3863 while ( eIt->more() && nbInitElems < 2 ) {
3865 SMDSAbs_ElementType type = el->GetType();
3866 if ( type == SMDSAbs_Volume || type < highType ) continue;
3867 if ( type > highType ) {
3871 if ( elemSet.find(el) != elemSet.end() )
3874 if ( nbInitElems < 2 ) {
3875 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3876 if(!NotCreateEdge) {
3877 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3878 list<const SMDS_MeshElement*> newEdges;
3879 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3884 // Make a ceiling for each element ie an equal element of last new nodes.
3885 // Find free links of faces - make edges and sweep them into faces.
3887 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3888 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3889 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3890 const SMDS_MeshElement* elem = itElem->first;
3891 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3893 if(itElem->second.size()==0) continue;
3895 if ( elem->GetType() == SMDSAbs_Edge ) {
3896 // create a ceiling edge
3897 if (!elem->IsQuadratic()) {
3898 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3899 vecNewNodes[ 1 ]->second.back())) {
3900 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3901 vecNewNodes[ 1 ]->second.back()));
3902 srcElements.Append( myLastCreatedElems.Last() );
3906 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3907 vecNewNodes[ 1 ]->second.back(),
3908 vecNewNodes[ 2 ]->second.back())) {
3909 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3910 vecNewNodes[ 1 ]->second.back(),
3911 vecNewNodes[ 2 ]->second.back()));
3912 srcElements.Append( myLastCreatedElems.Last() );
3916 if ( elem->GetType() != SMDSAbs_Face )
3919 bool hasFreeLinks = false;
3921 TIDSortedElemSet avoidSet;
3922 avoidSet.insert( elem );
3924 set<const SMDS_MeshNode*> aFaceLastNodes;
3925 int iNode, nbNodes = vecNewNodes.size();
3926 if(!elem->IsQuadratic()) {
3927 // loop on the face nodes
3928 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3929 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3930 // look for free links of the face
3931 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3932 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3933 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3934 // check if a link is free
3935 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3936 hasFreeLinks = true;
3937 // make an edge and a ceiling for a new edge
3938 if ( !aMesh->FindEdge( n1, n2 )) {
3939 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3940 srcElements.Append( myLastCreatedElems.Last() );
3942 n1 = vecNewNodes[ iNode ]->second.back();
3943 n2 = vecNewNodes[ iNext ]->second.back();
3944 if ( !aMesh->FindEdge( n1, n2 )) {
3945 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3946 srcElements.Append( myLastCreatedElems.Last() );
3951 else { // elem is quadratic face
3952 int nbn = nbNodes/2;
3953 for ( iNode = 0; iNode < nbn; iNode++ ) {
3954 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3955 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3956 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3957 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3958 // check if a link is free
3959 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3960 hasFreeLinks = true;
3961 // make an edge and a ceiling for a new edge
3963 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3964 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3965 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3966 srcElements.Append( myLastCreatedElems.Last() );
3968 n1 = vecNewNodes[ iNode ]->second.back();
3969 n2 = vecNewNodes[ iNext ]->second.back();
3970 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3971 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3972 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3973 srcElements.Append( myLastCreatedElems.Last() );
3977 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3978 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3982 // sweep free links into faces
3984 if ( hasFreeLinks ) {
3985 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3986 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3988 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3989 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3990 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3991 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3993 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3994 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3996 while ( iVol++ < volNb ) v++;
3997 // find indices of free faces of a volume and their source edges
3998 list< int > freeInd;
3999 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4000 SMDS_VolumeTool vTool( *v );
4001 int iF, nbF = vTool.NbFaces();
4002 for ( iF = 0; iF < nbF; iF ++ ) {
4003 if (vTool.IsFreeFace( iF ) &&
4004 vTool.GetFaceNodes( iF, faceNodeSet ) &&
4005 initNodeSet != faceNodeSet) // except an initial face
4007 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4009 freeInd.push_back( iF );
4010 // find source edge of a free face iF
4011 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4012 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4013 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4014 initNodeSet.begin(), initNodeSet.end(),
4015 commonNodes.begin());
4016 if ( (*v)->IsQuadratic() )
4017 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4019 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4021 if ( !srcEdges.back() )
4023 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4024 << iF << " of volume #" << vTool.ID() << endl;
4029 if ( freeInd.empty() )
4032 // create faces for all steps;
4033 // if such a face has been already created by sweep of edge,
4034 // assure that its orientation is OK
4035 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4037 vTool.SetExternalNormal();
4038 list< int >::iterator ind = freeInd.begin();
4039 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4040 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4042 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4043 int nbn = vTool.NbFaceNodes( *ind );
4045 case 3: { ///// triangle
4046 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4048 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4049 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4051 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4052 aMesh->RemoveElement(f);
4056 case 4: { ///// quadrangle
4057 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4059 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4060 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4062 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4063 aMesh->RemoveElement(f);
4068 if( (*v)->IsQuadratic() ) {
4069 if(nbn==6) { /////// quadratic triangle
4070 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4071 nodes[1], nodes[3], nodes[5] );
4073 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4074 nodes[1], nodes[3], nodes[5]));
4076 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4077 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4078 tmpnodes[0] = nodes[0];
4079 tmpnodes[1] = nodes[2];
4080 tmpnodes[2] = nodes[4];
4081 tmpnodes[3] = nodes[1];
4082 tmpnodes[4] = nodes[3];
4083 tmpnodes[5] = nodes[5];
4084 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4085 nodes[1], nodes[3], nodes[5]));
4086 aMesh->RemoveElement(f);
4089 else { /////// quadratic quadrangle
4090 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4091 nodes[1], nodes[3], nodes[5], nodes[7] );
4093 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4094 nodes[1], nodes[3], nodes[5], nodes[7]));
4096 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4097 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4098 tmpnodes[0] = nodes[0];
4099 tmpnodes[1] = nodes[2];
4100 tmpnodes[2] = nodes[4];
4101 tmpnodes[3] = nodes[6];
4102 tmpnodes[4] = nodes[1];
4103 tmpnodes[5] = nodes[3];
4104 tmpnodes[6] = nodes[5];
4105 tmpnodes[7] = nodes[7];
4106 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4107 nodes[1], nodes[3], nodes[5], nodes[7]));
4108 aMesh->RemoveElement(f);
4112 else { //////// polygon
4113 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4114 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4116 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4117 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4119 // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4120 MESSAGE("ChangeElementNodes");
4121 aMesh->ChangeElementNodes( f, nodes, nbn );
4125 while ( srcElements.Length() < myLastCreatedElems.Length() )
4126 srcElements.Append( *srcEdge );
4128 } // loop on free faces
4130 // go to the next volume
4132 while ( iVol++ < nbVolumesByStep ) v++;
4135 } // sweep free links into faces
4137 // Make a ceiling face with a normal external to a volume
4139 SMDS_VolumeTool lastVol( itElem->second.back() );
4141 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4143 lastVol.SetExternalNormal();
4144 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4145 int nbn = lastVol.NbFaceNodes( iF );
4148 if (!hasFreeLinks ||
4149 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4150 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4153 if (!hasFreeLinks ||
4154 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4155 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4158 if(itElem->second.back()->IsQuadratic()) {
4160 if (!hasFreeLinks ||
4161 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4162 nodes[1], nodes[3], nodes[5]) ) {
4163 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4164 nodes[1], nodes[3], nodes[5]));
4168 if (!hasFreeLinks ||
4169 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4170 nodes[1], nodes[3], nodes[5], nodes[7]) )
4171 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4172 nodes[1], nodes[3], nodes[5], nodes[7]));
4176 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4177 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4178 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4182 while ( srcElements.Length() < myLastCreatedElems.Length() )
4183 srcElements.Append( myLastCreatedElems.Last() );
4185 } // loop on swept elements
4188 //=======================================================================
4189 //function : RotationSweep
4191 //=======================================================================
4193 SMESH_MeshEditor::PGroupIDs
4194 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4195 const gp_Ax1& theAxis,
4196 const double theAngle,
4197 const int theNbSteps,
4198 const double theTol,
4199 const bool theMakeGroups,
4200 const bool theMakeWalls)
4202 myLastCreatedElems.Clear();
4203 myLastCreatedNodes.Clear();
4205 // source elements for each generated one
4206 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4208 MESSAGE( "RotationSweep()");
4210 aTrsf.SetRotation( theAxis, theAngle );
4212 aTrsf2.SetRotation( theAxis, theAngle/2. );
4214 gp_Lin aLine( theAxis );
4215 double aSqTol = theTol * theTol;
4217 SMESHDS_Mesh* aMesh = GetMeshDS();
4219 TNodeOfNodeListMap mapNewNodes;
4220 TElemOfVecOfNnlmiMap mapElemNewNodes;
4221 TElemOfElemListMap newElemsMap;
4224 TIDSortedElemSet::iterator itElem;
4225 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4226 const SMDS_MeshElement* elem = *itElem;
4227 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4229 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4230 newNodesItVec.reserve( elem->NbNodes() );
4232 // loop on elem nodes
4233 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4234 while ( itN->more() ) {
4235 // check if a node has been already sweeped
4236 const SMDS_MeshNode* node = cast2Node( itN->next() );
4238 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4240 aXYZ.Coord( coord[0], coord[1], coord[2] );
4241 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4243 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4244 if ( nIt == mapNewNodes.end() ) {
4245 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4246 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4249 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4251 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4252 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4253 const SMDS_MeshNode * newNode = node;
4254 for ( int i = 0; i < theNbSteps; i++ ) {
4256 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4258 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4259 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4260 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4261 myLastCreatedNodes.Append(newNode);
4262 srcNodes.Append( node );
4263 listNewNodes.push_back( newNode );
4264 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4265 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4268 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4270 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4271 myLastCreatedNodes.Append(newNode);
4272 srcNodes.Append( node );
4273 listNewNodes.push_back( newNode );
4276 listNewNodes.push_back( newNode );
4277 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4278 listNewNodes.push_back( newNode );
4285 // if current elem is quadratic and current node is not medium
4286 // we have to check - may be it is needed to insert additional nodes
4287 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4288 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4289 if(listNewNodes.size()==theNbSteps) {
4290 listNewNodes.clear();
4292 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4294 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4295 const SMDS_MeshNode * newNode = node;
4297 for(int i = 0; i<theNbSteps; i++) {
4298 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4299 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4300 cout<<" 3 AddNode: "<<newNode;
4301 myLastCreatedNodes.Append(newNode);
4302 listNewNodes.push_back( newNode );
4303 srcNodes.Append( node );
4304 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4305 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4306 cout<<" 4 AddNode: "<<newNode;
4307 myLastCreatedNodes.Append(newNode);
4308 srcNodes.Append( node );
4309 listNewNodes.push_back( newNode );
4313 listNewNodes.push_back( newNode );
4319 newNodesItVec.push_back( nIt );
4321 // make new elements
4322 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4326 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4328 PGroupIDs newGroupIDs;
4329 if ( theMakeGroups )
4330 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4336 //=======================================================================
4337 //function : CreateNode
4339 //=======================================================================
4340 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4343 const double tolnode,
4344 SMESH_SequenceOfNode& aNodes)
4346 myLastCreatedElems.Clear();
4347 myLastCreatedNodes.Clear();
4350 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4352 // try to search in sequence of existing nodes
4353 // if aNodes.Length()>0 we 'nave to use given sequence
4354 // else - use all nodes of mesh
4355 if(aNodes.Length()>0) {
4357 for(i=1; i<=aNodes.Length(); i++) {
4358 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4359 if(P1.Distance(P2)<tolnode)
4360 return aNodes.Value(i);
4364 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4365 while(itn->more()) {
4366 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4367 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4368 if(P1.Distance(P2)<tolnode)
4373 // create new node and return it
4374 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4375 myLastCreatedNodes.Append(NewNode);
4380 //=======================================================================
4381 //function : ExtrusionSweep
4383 //=======================================================================
4385 SMESH_MeshEditor::PGroupIDs
4386 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4387 const gp_Vec& theStep,
4388 const int theNbSteps,
4389 TElemOfElemListMap& newElemsMap,
4390 const bool theMakeGroups,
4392 const double theTolerance)
4394 ExtrusParam aParams;
4395 aParams.myDir = gp_Dir(theStep);
4396 aParams.myNodes.Clear();
4397 aParams.mySteps = new TColStd_HSequenceOfReal;
4399 for(i=1; i<=theNbSteps; i++)
4400 aParams.mySteps->Append(theStep.Magnitude());
4403 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4407 //=======================================================================
4408 //function : ExtrusionSweep
4410 //=======================================================================
4412 SMESH_MeshEditor::PGroupIDs
4413 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4414 ExtrusParam& theParams,
4415 TElemOfElemListMap& newElemsMap,
4416 const bool theMakeGroups,
4418 const double theTolerance)
4420 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4421 myLastCreatedElems.Clear();
4422 myLastCreatedNodes.Clear();
4424 // source elements for each generated one
4425 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4427 SMESHDS_Mesh* aMesh = GetMeshDS();
4429 int nbsteps = theParams.mySteps->Length();
4431 TNodeOfNodeListMap mapNewNodes;
4432 //TNodeOfNodeVecMap mapNewNodes;
4433 TElemOfVecOfNnlmiMap mapElemNewNodes;
4434 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4437 TIDSortedElemSet::iterator itElem;
4438 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4439 // check element type
4440 const SMDS_MeshElement* elem = *itElem;
4441 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4444 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4445 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4446 newNodesItVec.reserve( elem->NbNodes() );
4448 // loop on elem nodes
4449 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4450 while ( itN->more() )
4452 // check if a node has been already sweeped
4453 const SMDS_MeshNode* node = cast2Node( itN->next() );
4454 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4455 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4456 if ( nIt == mapNewNodes.end() ) {
4457 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4458 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4459 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4460 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4461 //vecNewNodes.reserve(nbsteps);
4464 double coord[] = { node->X(), node->Y(), node->Z() };
4465 //int nbsteps = theParams.mySteps->Length();
4466 for ( int i = 0; i < nbsteps; i++ ) {
4467 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4468 // create additional node
4469 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4470 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4471 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4472 if( theFlags & EXTRUSION_FLAG_SEW ) {
4473 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4474 theTolerance, theParams.myNodes);
4475 listNewNodes.push_back( newNode );
4478 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4479 myLastCreatedNodes.Append(newNode);
4480 srcNodes.Append( node );
4481 listNewNodes.push_back( newNode );
4484 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4485 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4486 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4487 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4488 if( theFlags & EXTRUSION_FLAG_SEW ) {
4489 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4490 theTolerance, theParams.myNodes);
4491 listNewNodes.push_back( newNode );
4492 //vecNewNodes[i]=newNode;
4495 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4496 myLastCreatedNodes.Append(newNode);
4497 srcNodes.Append( node );
4498 listNewNodes.push_back( newNode );
4499 //vecNewNodes[i]=newNode;
4504 // if current elem is quadratic and current node is not medium
4505 // we have to check - may be it is needed to insert additional nodes
4506 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4507 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4508 if(listNewNodes.size()==nbsteps) {
4509 listNewNodes.clear();
4510 double coord[] = { node->X(), node->Y(), node->Z() };
4511 for ( int i = 0; i < nbsteps; i++ ) {
4512 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4513 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4514 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4515 if( theFlags & EXTRUSION_FLAG_SEW ) {
4516 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4517 theTolerance, theParams.myNodes);
4518 listNewNodes.push_back( newNode );
4521 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4522 myLastCreatedNodes.Append(newNode);
4523 srcNodes.Append( node );
4524 listNewNodes.push_back( newNode );
4526 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4527 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4528 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4529 if( theFlags & EXTRUSION_FLAG_SEW ) {
4530 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4531 theTolerance, theParams.myNodes);
4532 listNewNodes.push_back( newNode );
4535 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4536 myLastCreatedNodes.Append(newNode);
4537 srcNodes.Append( node );
4538 listNewNodes.push_back( newNode );
4544 newNodesItVec.push_back( nIt );
4546 // make new elements
4547 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4550 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4551 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4553 PGroupIDs newGroupIDs;
4554 if ( theMakeGroups )
4555 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4561 //=======================================================================
4562 //class : SMESH_MeshEditor_PathPoint
4563 //purpose : auxiliary class
4564 //=======================================================================
4565 class SMESH_MeshEditor_PathPoint {
4567 SMESH_MeshEditor_PathPoint() {
4568 myPnt.SetCoord(99., 99., 99.);
4569 myTgt.SetCoord(1.,0.,0.);
4573 void SetPnt(const gp_Pnt& aP3D){
4576 void SetTangent(const gp_Dir& aTgt){
4579 void SetAngle(const double& aBeta){
4582 void SetParameter(const double& aPrm){
4585 const gp_Pnt& Pnt()const{
4588 const gp_Dir& Tangent()const{
4591 double Angle()const{
4594 double Parameter()const{
4606 //=======================================================================
4607 //function : ExtrusionAlongTrack
4609 //=======================================================================
4610 SMESH_MeshEditor::Extrusion_Error
4611 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4612 SMESH_subMesh* theTrack,
4613 const SMDS_MeshNode* theN1,
4614 const bool theHasAngles,
4615 list<double>& theAngles,
4616 const bool theLinearVariation,
4617 const bool theHasRefPoint,
4618 const gp_Pnt& theRefPoint,
4619 const bool theMakeGroups)
4621 MESSAGE("ExtrusionAlongTrack");
4622 myLastCreatedElems.Clear();
4623 myLastCreatedNodes.Clear();
4626 std::list<double> aPrms;
4627 TIDSortedElemSet::iterator itElem;
4630 TopoDS_Edge aTrackEdge;
4631 TopoDS_Vertex aV1, aV2;
4633 SMDS_ElemIteratorPtr aItE;
4634 SMDS_NodeIteratorPtr aItN;
4635 SMDSAbs_ElementType aTypeE;
4637 TNodeOfNodeListMap mapNewNodes;
4640 aNbE = theElements.size();
4643 return EXTR_NO_ELEMENTS;
4645 // 1.1 Track Pattern
4648 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4650 aItE = pSubMeshDS->GetElements();
4651 while ( aItE->more() ) {
4652 const SMDS_MeshElement* pE = aItE->next();
4653 aTypeE = pE->GetType();
4654 // Pattern must contain links only
4655 if ( aTypeE != SMDSAbs_Edge )
4656 return EXTR_PATH_NOT_EDGE;
4659 list<SMESH_MeshEditor_PathPoint> fullList;
4661 const TopoDS_Shape& aS = theTrack->GetSubShape();
4662 // Sub shape for the Pattern must be an Edge or Wire
4663 if( aS.ShapeType() == TopAbs_EDGE ) {
4664 aTrackEdge = TopoDS::Edge( aS );
4665 // the Edge must not be degenerated
4666 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4667 return EXTR_BAD_PATH_SHAPE;
4668 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4669 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4670 const SMDS_MeshNode* aN1 = aItN->next();
4671 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4672 const SMDS_MeshNode* aN2 = aItN->next();
4673 // starting node must be aN1 or aN2
4674 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4675 return EXTR_BAD_STARTING_NODE;
4676 aItN = pSubMeshDS->GetNodes();
4677 while ( aItN->more() ) {
4678 const SMDS_MeshNode* pNode = aItN->next();
4679 const SMDS_EdgePosition* pEPos =
4680 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4681 double aT = pEPos->GetUParameter();
4682 aPrms.push_back( aT );
4684 //Extrusion_Error err =
4685 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4687 else if( aS.ShapeType() == TopAbs_WIRE ) {
4688 list< SMESH_subMesh* > LSM;
4689 TopTools_SequenceOfShape Edges;
4690 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4691 while(itSM->more()) {
4692 SMESH_subMesh* SM = itSM->next();
4694 const TopoDS_Shape& aS = SM->GetSubShape();
4697 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4698 int startNid = theN1->GetID();
4699 TColStd_MapOfInteger UsedNums;
4700 int NbEdges = Edges.Length();
4702 for(; i<=NbEdges; i++) {
4704 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4705 for(; itLSM!=LSM.end(); itLSM++) {
4707 if(UsedNums.Contains(k)) continue;
4708 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4709 SMESH_subMesh* locTrack = *itLSM;
4710 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4711 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4712 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4713 const SMDS_MeshNode* aN1 = aItN->next();
4714 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4715 const SMDS_MeshNode* aN2 = aItN->next();
4716 // starting node must be aN1 or aN2
4717 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4718 // 2. Collect parameters on the track edge
4720 aItN = locMeshDS->GetNodes();
4721 while ( aItN->more() ) {
4722 const SMDS_MeshNode* pNode = aItN->next();
4723 const SMDS_EdgePosition* pEPos =
4724 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4725 double aT = pEPos->GetUParameter();
4726 aPrms.push_back( aT );
4728 list<SMESH_MeshEditor_PathPoint> LPP;
4729 //Extrusion_Error err =
4730 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4731 LLPPs.push_back(LPP);
4733 // update startN for search following egde
4734 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4735 else startNid = aN1->GetID();
4739 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4740 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4741 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4742 for(; itPP!=firstList.end(); itPP++) {
4743 fullList.push_back( *itPP );
4745 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4746 fullList.pop_back();
4748 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4749 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4750 itPP = currList.begin();
4751 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4752 gp_Dir D1 = PP1.Tangent();
4753 gp_Dir D2 = PP2.Tangent();
4754 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4755 (D1.Z()+D2.Z())/2 ) );
4756 PP1.SetTangent(Dnew);
4757 fullList.push_back(PP1);
4759 for(; itPP!=firstList.end(); itPP++) {
4760 fullList.push_back( *itPP );
4762 PP1 = fullList.back();
4763 fullList.pop_back();
4765 // if wire not closed
4766 fullList.push_back(PP1);
4770 return EXTR_BAD_PATH_SHAPE;
4773 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4774 theHasRefPoint, theRefPoint, theMakeGroups);
4778 //=======================================================================
4779 //function : ExtrusionAlongTrack
4781 //=======================================================================
4782 SMESH_MeshEditor::Extrusion_Error
4783 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4784 SMESH_Mesh* theTrack,
4785 const SMDS_MeshNode* theN1,
4786 const bool theHasAngles,
4787 list<double>& theAngles,
4788 const bool theLinearVariation,
4789 const bool theHasRefPoint,
4790 const gp_Pnt& theRefPoint,
4791 const bool theMakeGroups)
4793 myLastCreatedElems.Clear();
4794 myLastCreatedNodes.Clear();
4797 std::list<double> aPrms;
4798 TIDSortedElemSet::iterator itElem;
4801 TopoDS_Edge aTrackEdge;
4802 TopoDS_Vertex aV1, aV2;
4804 SMDS_ElemIteratorPtr aItE;
4805 SMDS_NodeIteratorPtr aItN;
4806 SMDSAbs_ElementType aTypeE;
4808 TNodeOfNodeListMap mapNewNodes;
4811 aNbE = theElements.size();
4814 return EXTR_NO_ELEMENTS;
4816 // 1.1 Track Pattern
4819 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4821 aItE = pMeshDS->elementsIterator();
4822 while ( aItE->more() ) {
4823 const SMDS_MeshElement* pE = aItE->next();
4824 aTypeE = pE->GetType();
4825 // Pattern must contain links only
4826 if ( aTypeE != SMDSAbs_Edge )
4827 return EXTR_PATH_NOT_EDGE;
4830 list<SMESH_MeshEditor_PathPoint> fullList;
4832 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4833 // Sub shape for the Pattern must be an Edge or Wire
4834 if( aS.ShapeType() == TopAbs_EDGE ) {
4835 aTrackEdge = TopoDS::Edge( aS );
4836 // the Edge must not be degenerated
4837 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4838 return EXTR_BAD_PATH_SHAPE;
4839 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4840 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4841 const SMDS_MeshNode* aN1 = aItN->next();
4842 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4843 const SMDS_MeshNode* aN2 = aItN->next();
4844 // starting node must be aN1 or aN2
4845 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4846 return EXTR_BAD_STARTING_NODE;
4847 aItN = pMeshDS->nodesIterator();
4848 while ( aItN->more() ) {
4849 const SMDS_MeshNode* pNode = aItN->next();
4850 if( pNode==aN1 || pNode==aN2 ) continue;
4851 const SMDS_EdgePosition* pEPos =
4852 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4853 double aT = pEPos->GetUParameter();
4854 aPrms.push_back( aT );
4856 //Extrusion_Error err =
4857 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4859 else if( aS.ShapeType() == TopAbs_WIRE ) {
4860 list< SMESH_subMesh* > LSM;
4861 TopTools_SequenceOfShape Edges;
4862 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4863 for(; eExp.More(); eExp.Next()) {
4864 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4865 if( BRep_Tool::Degenerated(E) ) continue;
4866 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4872 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4873 int startNid = theN1->GetID();
4874 TColStd_MapOfInteger UsedNums;
4875 int NbEdges = Edges.Length();
4877 for(; i<=NbEdges; i++) {
4879 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4880 for(; itLSM!=LSM.end(); itLSM++) {
4882 if(UsedNums.Contains(k)) continue;
4883 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4884 SMESH_subMesh* locTrack = *itLSM;
4885 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4886 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4887 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4888 const SMDS_MeshNode* aN1 = aItN->next();
4889 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4890 const SMDS_MeshNode* aN2 = aItN->next();
4891 // starting node must be aN1 or aN2
4892 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4893 // 2. Collect parameters on the track edge
4895 aItN = locMeshDS->GetNodes();
4896 while ( aItN->more() ) {
4897 const SMDS_MeshNode* pNode = aItN->next();
4898 const SMDS_EdgePosition* pEPos =
4899 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4900 double aT = pEPos->GetUParameter();
4901 aPrms.push_back( aT );
4903 list<SMESH_MeshEditor_PathPoint> LPP;
4904 //Extrusion_Error err =
4905 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4906 LLPPs.push_back(LPP);
4908 // update startN for search following egde
4909 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4910 else startNid = aN1->GetID();
4914 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4915 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4916 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4917 for(; itPP!=firstList.end(); itPP++) {
4918 fullList.push_back( *itPP );
4920 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4921 fullList.pop_back();
4923 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4924 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4925 itPP = currList.begin();
4926 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4927 gp_Pnt P1 = PP1.Pnt();
4928 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4929 gp_Pnt P2 = PP2.Pnt();
4930 gp_Dir D1 = PP1.Tangent();
4931 gp_Dir D2 = PP2.Tangent();
4932 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4933 (D1.Z()+D2.Z())/2 ) );
4934 PP1.SetTangent(Dnew);
4935 fullList.push_back(PP1);
4937 for(; itPP!=currList.end(); itPP++) {
4938 fullList.push_back( *itPP );
4940 PP1 = fullList.back();
4941 fullList.pop_back();
4943 // if wire not closed
4944 fullList.push_back(PP1);
4948 return EXTR_BAD_PATH_SHAPE;
4951 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4952 theHasRefPoint, theRefPoint, theMakeGroups);
4956 //=======================================================================
4957 //function : MakeEdgePathPoints
4958 //purpose : auxilary for ExtrusionAlongTrack
4959 //=======================================================================
4960 SMESH_MeshEditor::Extrusion_Error
4961 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4962 const TopoDS_Edge& aTrackEdge,
4964 list<SMESH_MeshEditor_PathPoint>& LPP)
4966 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4968 aTolVec2=aTolVec*aTolVec;
4970 TopoDS_Vertex aV1, aV2;
4971 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4972 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4973 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4974 // 2. Collect parameters on the track edge
4975 aPrms.push_front( aT1 );
4976 aPrms.push_back( aT2 );
4979 if( FirstIsStart ) {
4990 SMESH_MeshEditor_PathPoint aPP;
4991 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4992 std::list<double>::iterator aItD = aPrms.begin();
4993 for(; aItD != aPrms.end(); ++aItD) {
4997 aC3D->D1( aT, aP3D, aVec );
4998 aL2 = aVec.SquareMagnitude();
4999 if ( aL2 < aTolVec2 )
5000 return EXTR_CANT_GET_TANGENT;
5001 gp_Dir aTgt( aVec );
5003 aPP.SetTangent( aTgt );
5004 aPP.SetParameter( aT );
5011 //=======================================================================
5012 //function : MakeExtrElements
5013 //purpose : auxilary for ExtrusionAlongTrack
5014 //=======================================================================
5015 SMESH_MeshEditor::Extrusion_Error
5016 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5017 list<SMESH_MeshEditor_PathPoint>& fullList,
5018 const bool theHasAngles,
5019 list<double>& theAngles,
5020 const bool theLinearVariation,
5021 const bool theHasRefPoint,
5022 const gp_Pnt& theRefPoint,
5023 const bool theMakeGroups)
5025 MESSAGE("MakeExtrElements");
5026 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5027 int aNbTP = fullList.size();
5028 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5030 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5031 LinearAngleVariation(aNbTP-1, theAngles);
5033 vector<double> aAngles( aNbTP );
5035 for(; j<aNbTP; ++j) {
5038 if ( theHasAngles ) {
5040 std::list<double>::iterator aItD = theAngles.begin();
5041 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5043 aAngles[j] = anAngle;
5046 // fill vector of path points with angles
5047 //aPPs.resize(fullList.size());
5049 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5050 for(; itPP!=fullList.end(); itPP++) {
5052 SMESH_MeshEditor_PathPoint PP = *itPP;
5053 PP.SetAngle(aAngles[j]);
5057 TNodeOfNodeListMap mapNewNodes;
5058 TElemOfVecOfNnlmiMap mapElemNewNodes;
5059 TElemOfElemListMap newElemsMap;
5060 TIDSortedElemSet::iterator itElem;
5063 SMDSAbs_ElementType aTypeE;
5064 // source elements for each generated one
5065 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5067 // 3. Center of rotation aV0
5068 gp_Pnt aV0 = theRefPoint;
5070 if ( !theHasRefPoint ) {
5072 aGC.SetCoord( 0.,0.,0. );
5074 itElem = theElements.begin();
5075 for ( ; itElem != theElements.end(); itElem++ ) {
5076 const SMDS_MeshElement* elem = *itElem;
5078 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5079 while ( itN->more() ) {
5080 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5085 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5086 list<const SMDS_MeshNode*> aLNx;
5087 mapNewNodes[node] = aLNx;
5089 gp_XYZ aXYZ( aX, aY, aZ );
5097 } // if (!theHasRefPoint) {
5098 mapNewNodes.clear();
5100 // 4. Processing the elements
5101 SMESHDS_Mesh* aMesh = GetMeshDS();
5103 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5104 // check element type
5105 const SMDS_MeshElement* elem = *itElem;
5106 aTypeE = elem->GetType();
5107 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5110 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5111 newNodesItVec.reserve( elem->NbNodes() );
5113 // loop on elem nodes
5115 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5116 while ( itN->more() )
5119 // check if a node has been already processed
5120 const SMDS_MeshNode* node =
5121 static_cast<const SMDS_MeshNode*>( itN->next() );
5122 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5123 if ( nIt == mapNewNodes.end() ) {
5124 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5125 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5128 aX = node->X(); aY = node->Y(); aZ = node->Z();
5130 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5131 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5132 gp_Ax1 anAx1, anAxT1T0;
5133 gp_Dir aDT1x, aDT0x, aDT1T0;
5138 aPN0.SetCoord(aX, aY, aZ);
5140 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5142 aDT0x= aPP0.Tangent();
5143 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5145 for ( j = 1; j < aNbTP; ++j ) {
5146 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5148 aDT1x = aPP1.Tangent();
5149 aAngle1x = aPP1.Angle();
5151 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5153 gp_Vec aV01x( aP0x, aP1x );
5154 aTrsf.SetTranslation( aV01x );
5157 aV1x = aV0x.Transformed( aTrsf );
5158 aPN1 = aPN0.Transformed( aTrsf );
5160 // rotation 1 [ T1,T0 ]
5161 aAngleT1T0=-aDT1x.Angle( aDT0x );
5162 if (fabs(aAngleT1T0) > aTolAng) {
5164 anAxT1T0.SetLocation( aV1x );
5165 anAxT1T0.SetDirection( aDT1T0 );
5166 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5168 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5172 if ( theHasAngles ) {
5173 anAx1.SetLocation( aV1x );
5174 anAx1.SetDirection( aDT1x );
5175 aTrsfRot.SetRotation( anAx1, aAngle1x );
5177 aPN1 = aPN1.Transformed( aTrsfRot );
5181 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5182 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5183 // create additional node
5184 double x = ( aPN1.X() + aPN0.X() )/2.;
5185 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5186 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5187 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5188 myLastCreatedNodes.Append(newNode);
5189 srcNodes.Append( node );
5190 listNewNodes.push_back( newNode );
5195 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5196 myLastCreatedNodes.Append(newNode);
5197 srcNodes.Append( node );
5198 listNewNodes.push_back( newNode );
5208 // if current elem is quadratic and current node is not medium
5209 // we have to check - may be it is needed to insert additional nodes
5210 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5211 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5212 if(listNewNodes.size()==aNbTP-1) {
5213 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5214 gp_XYZ P(node->X(), node->Y(), node->Z());
5215 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5217 for(i=0; i<aNbTP-1; i++) {
5218 const SMDS_MeshNode* N = *it;
5219 double x = ( N->X() + P.X() )/2.;
5220 double y = ( N->Y() + P.Y() )/2.;
5221 double z = ( N->Z() + P.Z() )/2.;
5222 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5223 srcNodes.Append( node );
5224 myLastCreatedNodes.Append(newN);
5227 P = gp_XYZ(N->X(),N->Y(),N->Z());
5229 listNewNodes.clear();
5230 for(i=0; i<2*(aNbTP-1); i++) {
5231 listNewNodes.push_back(aNodes[i]);
5237 newNodesItVec.push_back( nIt );
5239 // make new elements
5240 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5241 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5242 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5245 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5247 if ( theMakeGroups )
5248 generateGroups( srcNodes, srcElems, "extruded");
5254 //=======================================================================
5255 //function : LinearAngleVariation
5256 //purpose : auxilary for ExtrusionAlongTrack
5257 //=======================================================================
5258 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5259 list<double>& Angles)
5261 int nbAngles = Angles.size();
5262 if( nbSteps > nbAngles ) {
5263 vector<double> theAngles(nbAngles);
5264 list<double>::iterator it = Angles.begin();
5266 for(; it!=Angles.end(); it++) {
5268 theAngles[i] = (*it);
5271 double rAn2St = double( nbAngles ) / double( nbSteps );
5272 double angPrev = 0, angle;
5273 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5274 double angCur = rAn2St * ( iSt+1 );
5275 double angCurFloor = floor( angCur );
5276 double angPrevFloor = floor( angPrev );
5277 if ( angPrevFloor == angCurFloor )
5278 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5280 int iP = int( angPrevFloor );
5281 double angPrevCeil = ceil(angPrev);
5282 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5284 int iC = int( angCurFloor );
5285 if ( iC < nbAngles )
5286 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5288 iP = int( angPrevCeil );
5290 angle += theAngles[ iC ];
5292 res.push_back(angle);
5297 for(; it!=res.end(); it++)
5298 Angles.push_back( *it );
5303 //================================================================================
5305 * \brief Move or copy theElements applying theTrsf to their nodes
5306 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5307 * \param theTrsf - transformation to apply
5308 * \param theCopy - if true, create translated copies of theElems
5309 * \param theMakeGroups - if true and theCopy, create translated groups
5310 * \param theTargetMesh - mesh to copy translated elements into
5311 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5313 //================================================================================
5315 SMESH_MeshEditor::PGroupIDs
5316 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5317 const gp_Trsf& theTrsf,
5319 const bool theMakeGroups,
5320 SMESH_Mesh* theTargetMesh)
5322 myLastCreatedElems.Clear();
5323 myLastCreatedNodes.Clear();
5325 bool needReverse = false;
5326 string groupPostfix;
5327 switch ( theTrsf.Form() ) {
5329 MESSAGE("gp_PntMirror");
5331 groupPostfix = "mirrored";
5334 MESSAGE("gp_Ax1Mirror");
5335 groupPostfix = "mirrored";
5338 MESSAGE("gp_Ax2Mirror");
5340 groupPostfix = "mirrored";
5343 MESSAGE("gp_Rotation");
5344 groupPostfix = "rotated";
5346 case gp_Translation:
5347 MESSAGE("gp_Translation");
5348 groupPostfix = "translated";
5351 MESSAGE("gp_Scale");
5352 groupPostfix = "scaled";
5354 case gp_CompoundTrsf: // different scale by axis
5355 MESSAGE("gp_CompoundTrsf");
5356 groupPostfix = "scaled";
5360 needReverse = false;
5361 groupPostfix = "transformed";
5364 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5365 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5366 SMESHDS_Mesh* aMesh = GetMeshDS();
5369 // map old node to new one
5370 TNodeNodeMap nodeMap;
5372 // elements sharing moved nodes; those of them which have all
5373 // nodes mirrored but are not in theElems are to be reversed
5374 TIDSortedElemSet inverseElemSet;
5376 // source elements for each generated one
5377 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5379 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5380 TIDSortedElemSet orphanNode;
5382 if ( theElems.empty() ) // transform the whole mesh
5385 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5386 while ( eIt->more() ) theElems.insert( eIt->next() );
5388 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5389 while ( nIt->more() )
5391 const SMDS_MeshNode* node = nIt->next();
5392 if ( node->NbInverseElements() == 0)
5393 orphanNode.insert( node );
5397 // loop on elements to transform nodes : first orphan nodes then elems
5398 TIDSortedElemSet::iterator itElem;
5399 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5400 for (int i=0; i<2; i++)
5401 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5402 const SMDS_MeshElement* elem = *itElem;
5406 // loop on elem nodes
5407 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5408 while ( itN->more() ) {
5410 const SMDS_MeshNode* node = cast2Node( itN->next() );
5411 // check if a node has been already transformed
5412 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5413 nodeMap.insert( make_pair ( node, node ));
5414 if ( !n2n_isnew.second )
5418 coord[0] = node->X();
5419 coord[1] = node->Y();
5420 coord[2] = node->Z();
5421 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5422 if ( theTargetMesh ) {
5423 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5424 n2n_isnew.first->second = newNode;
5425 myLastCreatedNodes.Append(newNode);
5426 srcNodes.Append( node );
5428 else if ( theCopy ) {
5429 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5430 n2n_isnew.first->second = newNode;
5431 myLastCreatedNodes.Append(newNode);
5432 srcNodes.Append( node );
5435 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5436 // node position on shape becomes invalid
5437 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5438 ( SMDS_SpacePosition::originSpacePosition() );
5441 // keep inverse elements
5442 if ( !theCopy && !theTargetMesh && needReverse ) {
5443 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5444 while ( invElemIt->more() ) {
5445 const SMDS_MeshElement* iel = invElemIt->next();
5446 inverseElemSet.insert( iel );
5452 // either create new elements or reverse mirrored ones
5453 if ( !theCopy && !needReverse && !theTargetMesh )
5456 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5457 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5458 theElems.insert( *invElemIt );
5460 // replicate or reverse elements
5461 // TODO revoir ordre reverse vtk
5463 REV_TETRA = 0, // = nbNodes - 4
5464 REV_PYRAMID = 1, // = nbNodes - 4
5465 REV_PENTA = 2, // = nbNodes - 4
5467 REV_HEXA = 4, // = nbNodes - 4
5471 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5472 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5473 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5474 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5475 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5476 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5479 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5481 const SMDS_MeshElement* elem = *itElem;
5482 if ( !elem || elem->GetType() == SMDSAbs_Node )
5485 int nbNodes = elem->NbNodes();
5486 int elemType = elem->GetType();
5488 if (elem->IsPoly()) {
5489 // Polygon or Polyhedral Volume
5490 switch ( elemType ) {
5493 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5495 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5496 while (itN->more()) {
5497 const SMDS_MeshNode* node =
5498 static_cast<const SMDS_MeshNode*>(itN->next());
5499 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5500 if (nodeMapIt == nodeMap.end())
5501 break; // not all nodes transformed
5503 // reverse mirrored faces and volumes
5504 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5506 poly_nodes[iNode] = (*nodeMapIt).second;
5510 if ( iNode != nbNodes )
5511 continue; // not all nodes transformed
5513 if ( theTargetMesh ) {
5514 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5515 srcElems.Append( elem );
5517 else if ( theCopy ) {
5518 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5519 srcElems.Append( elem );
5522 aMesh->ChangePolygonNodes(elem, poly_nodes);
5526 case SMDSAbs_Volume:
5528 // ATTENTION: Reversing is not yet done!!!
5529 const SMDS_VtkVolume* aPolyedre =
5530 dynamic_cast<const SMDS_VtkVolume*>( elem );
5532 MESSAGE("Warning: bad volumic element");
5536 vector<const SMDS_MeshNode*> poly_nodes;
5537 vector<int> quantities;
5539 bool allTransformed = true;
5540 int nbFaces = aPolyedre->NbFaces();
5541 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5542 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5543 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5544 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5545 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5546 if (nodeMapIt == nodeMap.end()) {
5547 allTransformed = false; // not all nodes transformed
5549 poly_nodes.push_back((*nodeMapIt).second);
5552 quantities.push_back(nbFaceNodes);
5554 if ( !allTransformed )
5555 continue; // not all nodes transformed
5557 if ( theTargetMesh ) {
5558 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5559 srcElems.Append( elem );
5561 else if ( theCopy ) {
5562 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5563 srcElems.Append( elem );
5566 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5576 int* i = index[ FORWARD ];
5577 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5578 if ( elemType == SMDSAbs_Face )
5579 i = index[ REV_FACE ];
5581 i = index[ nbNodes - 4 ];
5583 if(elem->IsQuadratic()) {
5584 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5587 if(nbNodes==3) { // quadratic edge
5588 static int anIds[] = {1,0,2};
5591 else if(nbNodes==6) { // quadratic triangle
5592 static int anIds[] = {0,2,1,5,4,3};
5595 else if(nbNodes==8) { // quadratic quadrangle
5596 static int anIds[] = {0,3,2,1,7,6,5,4};
5599 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5600 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5603 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5604 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5607 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5608 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5611 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5612 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5618 // find transformed nodes
5619 vector<const SMDS_MeshNode*> nodes(nbNodes);
5621 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5622 while ( itN->more() ) {
5623 const SMDS_MeshNode* node =
5624 static_cast<const SMDS_MeshNode*>( itN->next() );
5625 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5626 if ( nodeMapIt == nodeMap.end() )
5627 break; // not all nodes transformed
5628 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5630 if ( iNode != nbNodes )
5631 continue; // not all nodes transformed
5633 if ( theTargetMesh ) {
5634 if ( SMDS_MeshElement* copy =
5635 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5636 myLastCreatedElems.Append( copy );
5637 srcElems.Append( elem );
5640 else if ( theCopy ) {
5641 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5642 srcElems.Append( elem );
5645 // reverse element as it was reversed by transformation
5647 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5651 PGroupIDs newGroupIDs;
5653 if ( theMakeGroups && theCopy ||
5654 theMakeGroups && theTargetMesh )
5655 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5661 ////=======================================================================
5662 ////function : Scale
5664 ////=======================================================================
5666 //SMESH_MeshEditor::PGroupIDs
5667 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5668 // const gp_Pnt& thePoint,
5669 // const std::list<double>& theScaleFact,
5670 // const bool theCopy,
5671 // const bool theMakeGroups,
5672 // SMESH_Mesh* theTargetMesh)
5674 // MESSAGE("Scale");
5675 // myLastCreatedElems.Clear();
5676 // myLastCreatedNodes.Clear();
5678 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5679 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5680 // SMESHDS_Mesh* aMesh = GetMeshDS();
5682 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5683 // std::list<double>::const_iterator itS = theScaleFact.begin();
5685 // if(theScaleFact.size()==1) {
5689 // if(theScaleFact.size()==2) {
5694 // if(theScaleFact.size()>2) {
5701 // // map old node to new one
5702 // TNodeNodeMap nodeMap;
5704 // // elements sharing moved nodes; those of them which have all
5705 // // nodes mirrored but are not in theElems are to be reversed
5706 // TIDSortedElemSet inverseElemSet;
5708 // // source elements for each generated one
5709 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5711 // // loop on theElems
5712 // TIDSortedElemSet::iterator itElem;
5713 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5714 // const SMDS_MeshElement* elem = *itElem;
5718 // // loop on elem nodes
5719 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5720 // while ( itN->more() ) {
5722 // // check if a node has been already transformed
5723 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5724 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5725 // nodeMap.insert( make_pair ( node, node ));
5726 // if ( !n2n_isnew.second )
5729 // //double coord[3];
5730 // //coord[0] = node->X();
5731 // //coord[1] = node->Y();
5732 // //coord[2] = node->Z();
5733 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5734 // double dx = (node->X() - thePoint.X()) * scaleX;
5735 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5736 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5737 // if ( theTargetMesh ) {
5738 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5739 // const SMDS_MeshNode * newNode =
5740 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5741 // n2n_isnew.first->second = newNode;
5742 // myLastCreatedNodes.Append(newNode);
5743 // srcNodes.Append( node );
5745 // else if ( theCopy ) {
5746 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5747 // const SMDS_MeshNode * newNode =
5748 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5749 // n2n_isnew.first->second = newNode;
5750 // myLastCreatedNodes.Append(newNode);
5751 // srcNodes.Append( node );
5754 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5755 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5756 // // node position on shape becomes invalid
5757 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5758 // ( SMDS_SpacePosition::originSpacePosition() );
5761 // // keep inverse elements
5762 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5763 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5764 // // while ( invElemIt->more() ) {
5765 // // const SMDS_MeshElement* iel = invElemIt->next();
5766 // // inverseElemSet.insert( iel );
5772 // // either create new elements or reverse mirrored ones
5773 // //if ( !theCopy && !needReverse && !theTargetMesh )
5774 // if ( !theCopy && !theTargetMesh )
5775 // return PGroupIDs();
5777 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5778 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5779 // theElems.insert( *invElemIt );
5781 // // replicate or reverse elements
5784 // REV_TETRA = 0, // = nbNodes - 4
5785 // REV_PYRAMID = 1, // = nbNodes - 4
5786 // REV_PENTA = 2, // = nbNodes - 4
5788 // REV_HEXA = 4, // = nbNodes - 4
5791 // int index[][8] = {
5792 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5793 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5794 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5795 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5796 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5797 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5800 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5802 // const SMDS_MeshElement* elem = *itElem;
5803 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5806 // int nbNodes = elem->NbNodes();
5807 // int elemType = elem->GetType();
5809 // if (elem->IsPoly()) {
5810 // // Polygon or Polyhedral Volume
5811 // switch ( elemType ) {
5812 // case SMDSAbs_Face:
5814 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5816 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5817 // while (itN->more()) {
5818 // const SMDS_MeshNode* node =
5819 // static_cast<const SMDS_MeshNode*>(itN->next());
5820 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5821 // if (nodeMapIt == nodeMap.end())
5822 // break; // not all nodes transformed
5823 // //if (needReverse) {
5824 // // // reverse mirrored faces and volumes
5825 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5827 // poly_nodes[iNode] = (*nodeMapIt).second;
5831 // if ( iNode != nbNodes )
5832 // continue; // not all nodes transformed
5834 // if ( theTargetMesh ) {
5835 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5836 // srcElems.Append( elem );
5838 // else if ( theCopy ) {
5839 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5840 // srcElems.Append( elem );
5843 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5847 // case SMDSAbs_Volume:
5849 // // ATTENTION: Reversing is not yet done!!!
5850 // const SMDS_VtkVolume* aPolyedre =
5851 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5852 // if (!aPolyedre) {
5853 // MESSAGE("Warning: bad volumic element");
5857 // vector<const SMDS_MeshNode*> poly_nodes;
5858 // vector<int> quantities;
5860 // bool allTransformed = true;
5861 // int nbFaces = aPolyedre->NbFaces();
5862 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5863 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5864 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5865 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5866 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5867 // if (nodeMapIt == nodeMap.end()) {
5868 // allTransformed = false; // not all nodes transformed
5870 // poly_nodes.push_back((*nodeMapIt).second);
5873 // quantities.push_back(nbFaceNodes);
5875 // if ( !allTransformed )
5876 // continue; // not all nodes transformed
5878 // if ( theTargetMesh ) {
5879 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5880 // srcElems.Append( elem );
5882 // else if ( theCopy ) {
5883 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5884 // srcElems.Append( elem );
5887 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5896 // // Regular elements
5897 // int* i = index[ FORWARD ];
5898 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5899 // // if ( elemType == SMDSAbs_Face )
5900 // // i = index[ REV_FACE ];
5902 // // i = index[ nbNodes - 4 ];
5904 // if(elem->IsQuadratic()) {
5905 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5907 // //if(needReverse) {
5908 // // if(nbNodes==3) { // quadratic edge
5909 // // static int anIds[] = {1,0,2};
5912 // // else if(nbNodes==6) { // quadratic triangle
5913 // // static int anIds[] = {0,2,1,5,4,3};
5916 // // else if(nbNodes==8) { // quadratic quadrangle
5917 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5920 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5921 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5924 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5925 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5928 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5929 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5932 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5933 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5939 // // find transformed nodes
5940 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5942 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5943 // while ( itN->more() ) {
5944 // const SMDS_MeshNode* node =
5945 // static_cast<const SMDS_MeshNode*>( itN->next() );
5946 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5947 // if ( nodeMapIt == nodeMap.end() )
5948 // break; // not all nodes transformed
5949 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5951 // if ( iNode != nbNodes )
5952 // continue; // not all nodes transformed
5954 // if ( theTargetMesh ) {
5955 // if ( SMDS_MeshElement* copy =
5956 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5957 // myLastCreatedElems.Append( copy );
5958 // srcElems.Append( elem );
5961 // else if ( theCopy ) {
5962 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5963 // myLastCreatedElems.Append( copy );
5964 // srcElems.Append( elem );
5968 // // reverse element as it was reversed by transformation
5969 // if ( nbNodes > 2 )
5970 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5974 // PGroupIDs newGroupIDs;
5976 // if ( theMakeGroups && theCopy ||
5977 // theMakeGroups && theTargetMesh ) {
5978 // string groupPostfix = "scaled";
5979 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5982 // return newGroupIDs;
5986 //=======================================================================
5988 * \brief Create groups of elements made during transformation
5989 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5990 * \param elemGens - elements making corresponding myLastCreatedElems
5991 * \param postfix - to append to names of new groups
5993 //=======================================================================
5995 SMESH_MeshEditor::PGroupIDs
5996 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5997 const SMESH_SequenceOfElemPtr& elemGens,
5998 const std::string& postfix,
5999 SMESH_Mesh* targetMesh)
6001 PGroupIDs newGroupIDs( new list<int> );
6002 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6004 // Sort existing groups by types and collect their names
6006 // to store an old group and a generated new one
6007 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6008 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6010 set< string > groupNames;
6012 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6013 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6014 while ( groupIt->more() ) {
6015 SMESH_Group * group = groupIt->next();
6016 if ( !group ) continue;
6017 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6018 if ( !groupDS || groupDS->IsEmpty() ) continue;
6019 groupNames.insert( group->GetName() );
6020 groupDS->SetStoreName( group->GetName() );
6021 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6026 // loop on nodes and elements
6027 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6029 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6030 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6031 if ( gens.Length() != elems.Length() )
6032 throw SALOME_Exception(LOCALIZED("invalid args"));
6034 // loop on created elements
6035 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6037 const SMDS_MeshElement* sourceElem = gens( iElem );
6038 if ( !sourceElem ) {
6039 MESSAGE("generateGroups(): NULL source element");
6042 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6043 if ( groupsOldNew.empty() ) {
6044 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6045 ++iElem; // skip all elements made by sourceElem
6048 // collect all elements made by sourceElem
6049 list< const SMDS_MeshElement* > resultElems;
6050 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6051 if ( resElem != sourceElem )
6052 resultElems.push_back( resElem );
6053 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6054 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6055 if ( resElem != sourceElem )
6056 resultElems.push_back( resElem );
6057 // do not generate element groups from node ones
6058 if ( sourceElem->GetType() == SMDSAbs_Node &&
6059 elems( iElem )->GetType() != SMDSAbs_Node )
6062 // add resultElems to groups made by ones the sourceElem belongs to
6063 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6064 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6066 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6067 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6069 SMDS_MeshGroup* & newGroup = gOldNew->second;
6070 if ( !newGroup )// create a new group
6073 string name = oldGroup->GetStoreName();
6074 if ( !targetMesh ) {
6078 while ( !groupNames.insert( name ).second ) // name exists
6084 TCollection_AsciiString nbStr(nb+1);
6085 name.resize( name.rfind('_')+1 );
6086 name += nbStr.ToCString();
6093 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6095 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6096 newGroup = & groupDS->SMDSGroup();
6097 newGroupIDs->push_back( id );
6100 // fill in a new group
6101 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6102 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6103 newGroup->Add( *resElemIt );
6106 } // loop on created elements
6107 }// loop on nodes and elements
6112 //================================================================================
6114 * \brief Return list of group of nodes close to each other within theTolerance
6115 * Search among theNodes or in the whole mesh if theNodes is empty using
6116 * an Octree algorithm
6118 //================================================================================
6120 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6121 const double theTolerance,
6122 TListOfListOfNodes & theGroupsOfNodes)
6124 myLastCreatedElems.Clear();
6125 myLastCreatedNodes.Clear();
6127 if ( theNodes.empty() )
6128 { // get all nodes in the mesh
6129 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6130 while ( nIt->more() )
6131 theNodes.insert( theNodes.end(),nIt->next());
6134 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6138 //=======================================================================
6140 * \brief Implementation of search for the node closest to point
6142 //=======================================================================
6144 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6146 //---------------------------------------------------------------------
6148 * \brief Constructor
6150 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6152 myMesh = ( SMESHDS_Mesh* ) theMesh;
6154 TIDSortedNodeSet nodes;
6156 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6157 while ( nIt->more() )
6158 nodes.insert( nodes.end(), nIt->next() );
6160 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6162 // get max size of a leaf box
6163 SMESH_OctreeNode* tree = myOctreeNode;
6164 while ( !tree->isLeaf() )
6166 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6170 myHalfLeafSize = tree->maxSize() / 2.;
6173 //---------------------------------------------------------------------
6175 * \brief Move node and update myOctreeNode accordingly
6177 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6179 myOctreeNode->UpdateByMoveNode( node, toPnt );
6180 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6183 //---------------------------------------------------------------------
6185 * \brief Do it's job
6187 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6189 map<double, const SMDS_MeshNode*> dist2Nodes;
6190 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6191 if ( !dist2Nodes.empty() )
6192 return dist2Nodes.begin()->second;
6193 list<const SMDS_MeshNode*> nodes;
6194 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6196 double minSqDist = DBL_MAX;
6197 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6199 // sort leafs by their distance from thePnt
6200 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6201 TDistTreeMap treeMap;
6202 list< SMESH_OctreeNode* > treeList;
6203 list< SMESH_OctreeNode* >::iterator trIt;
6204 treeList.push_back( myOctreeNode );
6206 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6207 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6208 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6210 SMESH_OctreeNode* tree = *trIt;
6211 if ( !tree->isLeaf() ) // put children to the queue
6213 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6214 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6215 while ( cIt->more() )
6216 treeList.push_back( cIt->next() );
6218 else if ( tree->NbNodes() ) // put a tree to the treeMap
6220 const Bnd_B3d& box = tree->getBox();
6221 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6222 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6223 if ( !it_in.second ) // not unique distance to box center
6224 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6227 // find distance after which there is no sense to check tree's
6228 double sqLimit = DBL_MAX;
6229 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6230 if ( treeMap.size() > 5 ) {
6231 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6232 const Bnd_B3d& box = closestTree->getBox();
6233 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6234 sqLimit = limit * limit;
6236 // get all nodes from trees
6237 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6238 if ( sqDist_tree->first > sqLimit )
6240 SMESH_OctreeNode* tree = sqDist_tree->second;
6241 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6244 // find closest among nodes
6245 minSqDist = DBL_MAX;
6246 const SMDS_MeshNode* closestNode = 0;
6247 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6248 for ( ; nIt != nodes.end(); ++nIt ) {
6249 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6250 if ( minSqDist > sqDist ) {
6258 //---------------------------------------------------------------------
6262 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6264 //---------------------------------------------------------------------
6266 * \brief Return the node tree
6268 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6271 SMESH_OctreeNode* myOctreeNode;
6272 SMESHDS_Mesh* myMesh;
6273 double myHalfLeafSize; // max size of a leaf box
6276 //=======================================================================
6278 * \brief Return SMESH_NodeSearcher
6280 //=======================================================================
6282 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6284 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6287 // ========================================================================
6288 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6290 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6291 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6292 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6294 //=======================================================================
6296 * \brief Octal tree of bounding boxes of elements
6298 //=======================================================================
6300 class ElementBndBoxTree : public SMESH_Octree
6304 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6305 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6306 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6307 ~ElementBndBoxTree();
6310 ElementBndBoxTree() {}
6311 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6312 void buildChildrenData();
6313 Bnd_B3d* buildRootBox();
6315 //!< Bounding box of element
6316 struct ElementBox : public Bnd_B3d
6318 const SMDS_MeshElement* _element;
6319 int _refCount; // an ElementBox can be included in several tree branches
6320 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6322 vector< ElementBox* > _elements;
6325 //================================================================================
6327 * \brief ElementBndBoxTree creation
6329 //================================================================================
6331 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6332 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6334 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6335 _elements.reserve( nbElems );
6337 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6338 while ( elemIt->more() )
6339 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6341 if ( _elements.size() > MaxNbElemsInLeaf )
6347 //================================================================================
6351 //================================================================================
6353 ElementBndBoxTree::~ElementBndBoxTree()
6355 for ( int i = 0; i < _elements.size(); ++i )
6356 if ( --_elements[i]->_refCount <= 0 )
6357 delete _elements[i];
6360 //================================================================================
6362 * \brief Return the maximal box
6364 //================================================================================
6366 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6368 Bnd_B3d* box = new Bnd_B3d;
6369 for ( int i = 0; i < _elements.size(); ++i )
6370 box->Add( *_elements[i] );
6374 //================================================================================
6376 * \brief Redistrubute element boxes among children
6378 //================================================================================
6380 void ElementBndBoxTree::buildChildrenData()
6382 for ( int i = 0; i < _elements.size(); ++i )
6384 for (int j = 0; j < 8; j++)
6386 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6388 _elements[i]->_refCount++;
6389 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6392 _elements[i]->_refCount--;
6396 for (int j = 0; j < 8; j++)
6398 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6399 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6400 child->myIsLeaf = true;
6402 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6403 child->_elements.resize( child->_elements.size() ); // compact
6407 //================================================================================
6409 * \brief Return elements which can include the point
6411 //================================================================================
6413 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6414 TIDSortedElemSet& foundElems)
6416 if ( level() && getBox().IsOut( point.XYZ() ))
6421 for ( int i = 0; i < _elements.size(); ++i )
6422 if ( !_elements[i]->IsOut( point.XYZ() ))
6423 foundElems.insert( _elements[i]->_element );
6427 for (int i = 0; i < 8; i++)
6428 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6432 //================================================================================
6434 * \brief Return elements which can be intersected by the line
6436 //================================================================================
6438 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6439 TIDSortedElemSet& foundElems)
6441 if ( level() && getBox().IsOut( line ))
6446 for ( int i = 0; i < _elements.size(); ++i )
6447 if ( !_elements[i]->IsOut( line ))
6448 foundElems.insert( _elements[i]->_element );
6452 for (int i = 0; i < 8; i++)
6453 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6457 //================================================================================
6459 * \brief Construct the element box
6461 //================================================================================
6463 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6467 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6468 while ( nIt->more() )
6469 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6470 Enlarge( tolerance );
6475 //=======================================================================
6477 * \brief Implementation of search for the elements by point and
6478 * of classification of point in 2D mesh
6480 //=======================================================================
6482 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6484 SMESHDS_Mesh* _mesh;
6485 SMDS_ElemIteratorPtr _meshPartIt;
6486 ElementBndBoxTree* _ebbTree;
6487 SMESH_NodeSearcherImpl* _nodeSearcher;
6488 SMDSAbs_ElementType _elementType;
6490 bool _outerFacesFound;
6491 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6493 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6494 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6495 ~SMESH_ElementSearcherImpl()
6497 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6498 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6500 virtual int FindElementsByPoint(const gp_Pnt& point,
6501 SMDSAbs_ElementType type,
6502 vector< const SMDS_MeshElement* >& foundElements);
6503 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6505 void GetElementsNearLine( const gp_Ax1& line,
6506 SMDSAbs_ElementType type,
6507 vector< const SMDS_MeshElement* >& foundElems);
6508 double getTolerance();
6509 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6510 const double tolerance, double & param);
6511 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6512 bool isOuterBoundary(const SMDS_MeshElement* face) const
6514 return _outerFaces.empty() || _outerFaces.count(face);
6516 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6518 const SMDS_MeshElement* _face;
6520 bool _coincides; //!< the line lays in face plane
6521 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6522 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6524 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6527 TIDSortedElemSet _faces;
6528 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6529 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6533 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6535 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6536 << ", _coincides="<<i._coincides << ")";
6539 //=======================================================================
6541 * \brief define tolerance for search
6543 //=======================================================================
6545 double SMESH_ElementSearcherImpl::getTolerance()
6547 if ( _tolerance < 0 )
6549 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6552 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6554 double boxSize = _nodeSearcher->getTree()->maxSize();
6555 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6557 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6559 double boxSize = _ebbTree->maxSize();
6560 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6562 if ( _tolerance == 0 )
6564 // define tolerance by size of a most complex element
6565 int complexType = SMDSAbs_Volume;
6566 while ( complexType > SMDSAbs_All &&
6567 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6569 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6571 if ( complexType == int( SMDSAbs_Node ))
6573 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6575 if ( meshInfo.NbNodes() > 2 )
6576 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6580 SMDS_ElemIteratorPtr elemIt =
6581 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6582 const SMDS_MeshElement* elem = elemIt->next();
6583 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6584 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6586 while ( nodeIt->more() )
6588 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6589 elemSize = max( dist, elemSize );
6592 _tolerance = 1e-4 * elemSize;
6598 //================================================================================
6600 * \brief Find intersection of the line and an edge of face and return parameter on line
6602 //================================================================================
6604 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6605 const SMDS_MeshElement* face,
6612 GeomAPI_ExtremaCurveCurve anExtCC;
6613 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6615 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6616 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6618 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6619 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6620 anExtCC.Init( lineCurve, edge);
6621 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6623 Quantity_Parameter pl, pe;
6624 anExtCC.LowerDistanceParameters( pl, pe );
6626 if ( ++nbInts == 2 )
6630 if ( nbInts > 0 ) param /= nbInts;
6633 //================================================================================
6635 * \brief Find all faces belonging to the outer boundary of mesh
6637 //================================================================================
6639 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6641 if ( _outerFacesFound ) return;
6643 // Collect all outer faces by passing from one outer face to another via their links
6644 // and BTW find out if there are internal faces at all.
6646 // checked links and links where outer boundary meets internal one
6647 set< SMESH_TLink > visitedLinks, seamLinks;
6649 // links to treat with already visited faces sharing them
6650 list < TFaceLink > startLinks;
6652 // load startLinks with the first outerFace
6653 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6654 _outerFaces.insert( outerFace );
6656 TIDSortedElemSet emptySet;
6657 while ( !startLinks.empty() )
6659 const SMESH_TLink& link = startLinks.front()._link;
6660 TIDSortedElemSet& faces = startLinks.front()._faces;
6662 outerFace = *faces.begin();
6663 // find other faces sharing the link
6664 const SMDS_MeshElement* f;
6665 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6668 // select another outer face among the found
6669 const SMDS_MeshElement* outerFace2 = 0;
6670 if ( faces.size() == 2 )
6672 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6674 else if ( faces.size() > 2 )
6676 seamLinks.insert( link );
6678 // link direction within the outerFace
6679 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6680 SMESH_TNodeXYZ( link.node2()));
6681 int i1 = outerFace->GetNodeIndex( link.node1() );
6682 int i2 = outerFace->GetNodeIndex( link.node2() );
6683 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6684 if ( rev ) n1n2.Reverse();
6686 gp_XYZ ofNorm, fNorm;
6687 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6689 // direction from the link inside outerFace
6690 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6691 // sort all other faces by angle with the dirInOF
6692 map< double, const SMDS_MeshElement* > angle2Face;
6693 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6694 for ( ; face != faces.end(); ++face )
6696 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6698 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6699 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6700 if ( angle < 0 ) angle += 2*PI;
6701 angle2Face.insert( make_pair( angle, *face ));
6703 if ( !angle2Face.empty() )
6704 outerFace2 = angle2Face.begin()->second;
6707 // store the found outer face and add its links to continue seaching from
6710 _outerFaces.insert( outerFace );
6711 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6712 for ( int i = 0; i < nbNodes; ++i )
6714 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6715 if ( visitedLinks.insert( link2 ).second )
6716 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6719 startLinks.pop_front();
6721 _outerFacesFound = true;
6723 if ( !seamLinks.empty() )
6725 // There are internal boundaries touching the outher one,
6726 // find all faces of internal boundaries in order to find
6727 // faces of boundaries of holes, if any.
6732 _outerFaces.clear();
6736 //=======================================================================
6738 * \brief Find elements of given type where the given point is IN or ON.
6739 * Returns nb of found elements and elements them-selves.
6741 * 'ALL' type means elements of any type excluding nodes and 0D elements
6743 //=======================================================================
6745 int SMESH_ElementSearcherImpl::
6746 FindElementsByPoint(const gp_Pnt& point,
6747 SMDSAbs_ElementType type,
6748 vector< const SMDS_MeshElement* >& foundElements)
6750 foundElements.clear();
6752 double tolerance = getTolerance();
6754 // =================================================================================
6755 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6757 if ( !_nodeSearcher )
6758 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6760 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6761 if ( !closeNode ) return foundElements.size();
6763 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6764 return foundElements.size(); // to far from any node
6766 if ( type == SMDSAbs_Node )
6768 foundElements.push_back( closeNode );
6772 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6773 while ( elemIt->more() )
6774 foundElements.push_back( elemIt->next() );
6777 // =================================================================================
6778 else // elements more complex than 0D
6780 if ( !_ebbTree || _elementType != type )
6782 if ( _ebbTree ) delete _ebbTree;
6783 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6785 TIDSortedElemSet suspectElems;
6786 _ebbTree->getElementsNearPoint( point, suspectElems );
6787 TIDSortedElemSet::iterator elem = suspectElems.begin();
6788 for ( ; elem != suspectElems.end(); ++elem )
6789 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6790 foundElements.push_back( *elem );
6792 return foundElements.size();
6795 //================================================================================
6797 * \brief Classify the given point in the closed 2D mesh
6799 //================================================================================
6801 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6803 double tolerance = getTolerance();
6804 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6806 if ( _ebbTree ) delete _ebbTree;
6807 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6809 // Algo: analyse transition of a line starting at the point through mesh boundary;
6810 // try three lines parallel to axis of the coordinate system and perform rough
6811 // analysis. If solution is not clear perform thorough analysis.
6813 const int nbAxes = 3;
6814 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6815 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6816 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6817 multimap< int, int > nbInt2Axis; // to find the simplest case
6818 for ( int axis = 0; axis < nbAxes; ++axis )
6820 gp_Ax1 lineAxis( point, axisDir[axis]);
6821 gp_Lin line ( lineAxis );
6823 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6824 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6826 // Intersect faces with the line
6828 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6829 TIDSortedElemSet::iterator face = suspectFaces.begin();
6830 for ( ; face != suspectFaces.end(); ++face )
6834 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6835 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6837 // perform intersection
6838 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6839 if ( !intersection.IsDone() )
6841 if ( intersection.IsInQuadric() )
6843 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6845 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6847 gp_Pnt intersectionPoint = intersection.Point(1);
6848 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6849 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6852 // Analyse intersections roughly
6854 int nbInter = u2inters.size();
6858 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6859 if ( nbInter == 1 ) // not closed mesh
6860 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6862 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6865 if ( (f<0) == (l<0) )
6868 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6869 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6870 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6873 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6875 if ( _outerFacesFound ) break; // pass to thorough analysis
6877 } // three attempts - loop on CS axes
6879 // Analyse intersections thoroughly.
6880 // We make two loops maximum, on the first one we only exclude touching intersections,
6881 // on the second, if situation is still unclear, we gather and use information on
6882 // position of faces (internal or outer). If faces position is already gathered,
6883 // we make the second loop right away.
6885 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6887 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6888 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6890 int axis = nb_axis->second;
6891 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6893 gp_Ax1 lineAxis( point, axisDir[axis]);
6894 gp_Lin line ( lineAxis );
6896 // add tangent intersections to u2inters
6898 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6899 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6900 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6901 u2inters.insert(make_pair( param, *tgtInt ));
6902 tangentInters[ axis ].clear();
6904 // Count intersections before and after the point excluding touching ones.
6905 // If hasPositionInfo we count intersections of outer boundary only
6907 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6908 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6909 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6910 bool ok = ! u_int1->second._coincides;
6911 while ( ok && u_int1 != u2inters.end() )
6913 double u = u_int1->first;
6914 bool touchingInt = false;
6915 if ( ++u_int2 != u2inters.end() )
6917 // skip intersections at the same point (if the line passes through edge or node)
6919 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6925 // skip tangent intersections
6927 const SMDS_MeshElement* prevFace = u_int1->second._face;
6928 while ( ok && u_int2->second._coincides )
6930 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6936 ok = ( u_int2 != u2inters.end() );
6941 // skip intersections at the same point after tangent intersections
6944 double u2 = u_int2->first;
6946 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6952 // decide if we skipped a touching intersection
6953 if ( nbSamePnt + nbTgt > 0 )
6955 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6956 map< double, TInters >::iterator u_int = u_int1;
6957 for ( ; u_int != u_int2; ++u_int )
6959 if ( u_int->second._coincides ) continue;
6960 double dot = u_int->second._faceNorm * line.Direction();
6961 if ( dot > maxDot ) maxDot = dot;
6962 if ( dot < minDot ) minDot = dot;
6964 touchingInt = ( minDot*maxDot < 0 );
6969 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6980 u_int1 = u_int2; // to next intersection
6982 } // loop on intersections with one line
6986 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6989 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6992 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6993 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6995 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6998 if ( (f<0) == (l<0) )
7001 if ( hasPositionInfo )
7002 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7004 } // loop on intersections of the tree lines - thorough analysis
7006 if ( !hasPositionInfo )
7008 // gather info on faces position - is face in the outer boundary or not
7009 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7010 findOuterBoundary( u2inters.begin()->second._face );
7013 } // two attempts - with and w/o faces position info in the mesh
7015 return TopAbs_UNKNOWN;
7018 //=======================================================================
7020 * \brief Return elements possibly intersecting the line
7022 //=======================================================================
7024 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7025 SMDSAbs_ElementType type,
7026 vector< const SMDS_MeshElement* >& foundElems)
7028 if ( !_ebbTree || _elementType != type )
7030 if ( _ebbTree ) delete _ebbTree;
7031 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7033 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7034 _ebbTree->getElementsNearLine( line, suspectFaces );
7035 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7038 //=======================================================================
7040 * \brief Return SMESH_ElementSearcher
7042 //=======================================================================
7044 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7046 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7049 //=======================================================================
7051 * \brief Return SMESH_ElementSearcher
7053 //=======================================================================
7055 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7057 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7060 //=======================================================================
7062 * \brief Return true if the point is IN or ON of the element
7064 //=======================================================================
7066 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7068 if ( element->GetType() == SMDSAbs_Volume)
7070 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7073 // get ordered nodes
7075 vector< gp_XYZ > xyz;
7076 vector<const SMDS_MeshNode*> nodeList;
7078 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7079 if ( element->IsQuadratic() ) {
7080 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7081 nodeIt = f->interlacedNodesElemIterator();
7082 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7083 nodeIt = e->interlacedNodesElemIterator();
7085 while ( nodeIt->more() )
7087 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7088 xyz.push_back( SMESH_TNodeXYZ(node) );
7089 nodeList.push_back(node);
7092 int i, nbNodes = element->NbNodes();
7094 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7096 // compute face normal
7097 gp_Vec faceNorm(0,0,0);
7098 xyz.push_back( xyz.front() );
7099 nodeList.push_back( nodeList.front() );
7100 for ( i = 0; i < nbNodes; ++i )
7102 gp_Vec edge1( xyz[i+1], xyz[i]);
7103 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7104 faceNorm += edge1 ^ edge2;
7106 double normSize = faceNorm.Magnitude();
7107 if ( normSize <= tol )
7109 // degenerated face: point is out if it is out of all face edges
7110 for ( i = 0; i < nbNodes; ++i )
7112 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7113 if ( !isOut( &edge, point, tol ))
7118 faceNorm /= normSize;
7120 // check if the point lays on face plane
7121 gp_Vec n2p( xyz[0], point );
7122 if ( fabs( n2p * faceNorm ) > tol )
7123 return true; // not on face plane
7125 // check if point is out of face boundary:
7126 // define it by closest transition of a ray point->infinity through face boundary
7127 // on the face plane.
7128 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7129 // to find intersections of the ray with the boundary.
7131 gp_Vec plnNorm = ray ^ faceNorm;
7132 normSize = plnNorm.Magnitude();
7133 if ( normSize <= tol ) return false; // point coincides with the first node
7134 plnNorm /= normSize;
7135 // for each node of the face, compute its signed distance to the plane
7136 vector<double> dist( nbNodes + 1);
7137 for ( i = 0; i < nbNodes; ++i )
7139 gp_Vec n2p( xyz[i], point );
7140 dist[i] = n2p * plnNorm;
7142 dist.back() = dist.front();
7143 // find the closest intersection
7145 double rClosest, distClosest = 1e100;;
7147 for ( i = 0; i < nbNodes; ++i )
7150 if ( fabs( dist[i]) < tol )
7152 else if ( fabs( dist[i+1]) < tol )
7154 else if ( dist[i] * dist[i+1] < 0 )
7155 r = dist[i] / ( dist[i] - dist[i+1] );
7157 continue; // no intersection
7158 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7159 gp_Vec p2int ( point, pInt);
7160 if ( p2int * ray > -tol ) // right half-space
7162 double intDist = p2int.SquareMagnitude();
7163 if ( intDist < distClosest )
7168 distClosest = intDist;
7173 return true; // no intesections - out
7175 // analyse transition
7176 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7177 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7178 gp_Vec p2int ( point, pClosest );
7179 bool out = (edgeNorm * p2int) < -tol;
7180 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7183 // ray pass through a face node; analyze transition through an adjacent edge
7184 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7185 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7186 gp_Vec edgeAdjacent( p1, p2 );
7187 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7188 bool out2 = (edgeNorm2 * p2int) < -tol;
7190 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7191 return covexCorner ? (out || out2) : (out && out2);
7193 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7195 // point is out of edge if it is NOT ON any straight part of edge
7196 // (we consider quadratic edge as being composed of two straight parts)
7197 for ( i = 1; i < nbNodes; ++i )
7199 gp_Vec edge( xyz[i-1], xyz[i]);
7200 gp_Vec n1p ( xyz[i-1], point);
7201 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7204 gp_Vec n2p( xyz[i], point );
7205 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7207 return false; // point is ON this part
7211 // Node or 0D element -------------------------------------------------------------------------
7213 gp_Vec n2p ( xyz[0], point );
7214 return n2p.Magnitude() <= tol;
7219 //=======================================================================
7220 //function : SimplifyFace
7222 //=======================================================================
7223 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7224 vector<const SMDS_MeshNode *>& poly_nodes,
7225 vector<int>& quantities) const
7227 int nbNodes = faceNodes.size();
7232 set<const SMDS_MeshNode*> nodeSet;
7234 // get simple seq of nodes
7235 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7236 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7237 int iSimple = 0, nbUnique = 0;
7239 simpleNodes[iSimple++] = faceNodes[0];
7241 for (int iCur = 1; iCur < nbNodes; iCur++) {
7242 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7243 simpleNodes[iSimple++] = faceNodes[iCur];
7244 if (nodeSet.insert( faceNodes[iCur] ).second)
7248 int nbSimple = iSimple;
7249 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7259 bool foundLoop = (nbSimple > nbUnique);
7262 set<const SMDS_MeshNode*> loopSet;
7263 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7264 const SMDS_MeshNode* n = simpleNodes[iSimple];
7265 if (!loopSet.insert( n ).second) {
7269 int iC = 0, curLast = iSimple;
7270 for (; iC < curLast; iC++) {
7271 if (simpleNodes[iC] == n) break;
7273 int loopLen = curLast - iC;
7275 // create sub-element
7277 quantities.push_back(loopLen);
7278 for (; iC < curLast; iC++) {
7279 poly_nodes.push_back(simpleNodes[iC]);
7282 // shift the rest nodes (place from the first loop position)
7283 for (iC = curLast + 1; iC < nbSimple; iC++) {
7284 simpleNodes[iC - loopLen] = simpleNodes[iC];
7286 nbSimple -= loopLen;
7289 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7290 } // while (foundLoop)
7294 quantities.push_back(iSimple);
7295 for (int i = 0; i < iSimple; i++)
7296 poly_nodes.push_back(simpleNodes[i]);
7302 //=======================================================================
7303 //function : MergeNodes
7304 //purpose : In each group, the cdr of nodes are substituted by the first one
7306 //=======================================================================
7308 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7310 MESSAGE("MergeNodes");
7311 myLastCreatedElems.Clear();
7312 myLastCreatedNodes.Clear();
7314 SMESHDS_Mesh* aMesh = GetMeshDS();
7316 TNodeNodeMap nodeNodeMap; // node to replace - new node
7317 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7318 list< int > rmElemIds, rmNodeIds;
7320 // Fill nodeNodeMap and elems
7322 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7323 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7324 list<const SMDS_MeshNode*>& nodes = *grIt;
7325 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7326 const SMDS_MeshNode* nToKeep = *nIt;
7327 //MESSAGE("node to keep " << nToKeep->GetID());
7328 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7329 const SMDS_MeshNode* nToRemove = *nIt;
7330 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7331 if ( nToRemove != nToKeep ) {
7332 //MESSAGE(" node to remove " << nToRemove->GetID());
7333 rmNodeIds.push_back( nToRemove->GetID() );
7334 AddToSameGroups( nToKeep, nToRemove, aMesh );
7337 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7338 while ( invElemIt->more() ) {
7339 const SMDS_MeshElement* elem = invElemIt->next();
7344 // Change element nodes or remove an element
7346 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7347 for ( ; eIt != elems.end(); eIt++ ) {
7348 const SMDS_MeshElement* elem = *eIt;
7349 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7350 int nbNodes = elem->NbNodes();
7351 int aShapeId = FindShape( elem );
7353 set<const SMDS_MeshNode*> nodeSet;
7354 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7355 int iUnique = 0, iCur = 0, nbRepl = 0;
7356 vector<int> iRepl( nbNodes );
7358 // get new seq of nodes
7359 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7360 while ( itN->more() ) {
7361 const SMDS_MeshNode* n =
7362 static_cast<const SMDS_MeshNode*>( itN->next() );
7364 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7365 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7367 // BUG 0020185: begin
7369 bool stopRecur = false;
7370 set<const SMDS_MeshNode*> nodesRecur;
7371 nodesRecur.insert(n);
7372 while (!stopRecur) {
7373 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7374 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7375 n = (*nnIt_i).second;
7376 if (!nodesRecur.insert(n).second) {
7377 // error: recursive dependancy
7386 iRepl[ nbRepl++ ] = iCur;
7388 curNodes[ iCur ] = n;
7389 bool isUnique = nodeSet.insert( n ).second;
7391 uniqueNodes[ iUnique++ ] = n;
7395 // Analyse element topology after replacement
7398 int nbUniqueNodes = nodeSet.size();
7399 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7400 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7401 // Polygons and Polyhedral volumes
7402 if (elem->IsPoly()) {
7404 if (elem->GetType() == SMDSAbs_Face) {
7406 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7408 for (; inode < nbNodes; inode++) {
7409 face_nodes[inode] = curNodes[inode];
7412 vector<const SMDS_MeshNode *> polygons_nodes;
7413 vector<int> quantities;
7414 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7417 for (int iface = 0; iface < nbNew; iface++) {
7418 int nbNodes = quantities[iface];
7419 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7420 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7421 poly_nodes[ii] = polygons_nodes[inode];
7423 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7424 myLastCreatedElems.Append(newElem);
7426 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7429 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7430 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7431 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7433 if (nbNew > 0) quid = nbNew - 1;
7434 vector<int> newquant(quantities.begin()+quid, quantities.end());
7435 const SMDS_MeshElement* newElem = 0;
7436 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7437 myLastCreatedElems.Append(newElem);
7438 if ( aShapeId && newElem )
7439 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7440 rmElemIds.push_back(elem->GetID());
7443 rmElemIds.push_back(elem->GetID());
7447 else if (elem->GetType() == SMDSAbs_Volume) {
7448 // Polyhedral volume
7449 if (nbUniqueNodes < 4) {
7450 rmElemIds.push_back(elem->GetID());
7453 // each face has to be analyzed in order to check volume validity
7454 const SMDS_VtkVolume* aPolyedre =
7455 dynamic_cast<const SMDS_VtkVolume*>( elem );
7457 int nbFaces = aPolyedre->NbFaces();
7459 vector<const SMDS_MeshNode *> poly_nodes;
7460 vector<int> quantities;
7462 for (int iface = 1; iface <= nbFaces; iface++) {
7463 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7464 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7466 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7467 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7468 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7469 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7470 faceNode = (*nnIt).second;
7472 faceNodes[inode - 1] = faceNode;
7475 SimplifyFace(faceNodes, poly_nodes, quantities);
7478 if (quantities.size() > 3) {
7479 // to be done: remove coincident faces
7482 if (quantities.size() > 3)
7484 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7485 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7486 const SMDS_MeshElement* newElem = 0;
7487 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7488 myLastCreatedElems.Append(newElem);
7489 if ( aShapeId && newElem )
7490 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7491 rmElemIds.push_back(elem->GetID());
7495 rmElemIds.push_back(elem->GetID());
7506 // TODO not all the possible cases are solved. Find something more generic?
7507 switch ( nbNodes ) {
7508 case 2: ///////////////////////////////////// EDGE
7509 isOk = false; break;
7510 case 3: ///////////////////////////////////// TRIANGLE
7511 isOk = false; break;
7513 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7515 else { //////////////////////////////////// QUADRANGLE
7516 if ( nbUniqueNodes < 3 )
7518 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7519 isOk = false; // opposite nodes stick
7520 //MESSAGE("isOk " << isOk);
7523 case 6: ///////////////////////////////////// PENTAHEDRON
7524 if ( nbUniqueNodes == 4 ) {
7525 // ---------------------------------> tetrahedron
7527 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7528 // all top nodes stick: reverse a bottom
7529 uniqueNodes[ 0 ] = curNodes [ 1 ];
7530 uniqueNodes[ 1 ] = curNodes [ 0 ];
7532 else if (nbRepl == 3 &&
7533 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7534 // all bottom nodes stick: set a top before
7535 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7536 uniqueNodes[ 0 ] = curNodes [ 3 ];
7537 uniqueNodes[ 1 ] = curNodes [ 4 ];
7538 uniqueNodes[ 2 ] = curNodes [ 5 ];
7540 else if (nbRepl == 4 &&
7541 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7542 // a lateral face turns into a line: reverse a bottom
7543 uniqueNodes[ 0 ] = curNodes [ 1 ];
7544 uniqueNodes[ 1 ] = curNodes [ 0 ];
7549 else if ( nbUniqueNodes == 5 ) {
7550 // PENTAHEDRON --------------------> 2 tetrahedrons
7551 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7552 // a bottom node sticks with a linked top one
7554 SMDS_MeshElement* newElem =
7555 aMesh->AddVolume(curNodes[ 3 ],
7558 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7559 myLastCreatedElems.Append(newElem);
7561 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7562 // 2. : reverse a bottom
7563 uniqueNodes[ 0 ] = curNodes [ 1 ];
7564 uniqueNodes[ 1 ] = curNodes [ 0 ];
7574 if(elem->IsQuadratic()) { // Quadratic quadrangle
7586 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7589 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7591 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7592 uniqueNodes[0] = curNodes[0];
7593 uniqueNodes[1] = curNodes[2];
7594 uniqueNodes[2] = curNodes[3];
7595 uniqueNodes[3] = curNodes[5];
7596 uniqueNodes[4] = curNodes[6];
7597 uniqueNodes[5] = curNodes[7];
7600 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7601 uniqueNodes[0] = curNodes[0];
7602 uniqueNodes[1] = curNodes[1];
7603 uniqueNodes[2] = curNodes[2];
7604 uniqueNodes[3] = curNodes[4];
7605 uniqueNodes[4] = curNodes[5];
7606 uniqueNodes[5] = curNodes[6];
7609 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7610 uniqueNodes[0] = curNodes[1];
7611 uniqueNodes[1] = curNodes[2];
7612 uniqueNodes[2] = curNodes[3];
7613 uniqueNodes[3] = curNodes[5];
7614 uniqueNodes[4] = curNodes[6];
7615 uniqueNodes[5] = curNodes[0];
7618 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7619 uniqueNodes[0] = curNodes[0];
7620 uniqueNodes[1] = curNodes[1];
7621 uniqueNodes[2] = curNodes[3];
7622 uniqueNodes[3] = curNodes[4];
7623 uniqueNodes[4] = curNodes[6];
7624 uniqueNodes[5] = curNodes[7];
7627 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7628 uniqueNodes[0] = curNodes[0];
7629 uniqueNodes[1] = curNodes[2];
7630 uniqueNodes[2] = curNodes[3];
7631 uniqueNodes[3] = curNodes[1];
7632 uniqueNodes[4] = curNodes[6];
7633 uniqueNodes[5] = curNodes[7];
7636 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7637 uniqueNodes[0] = curNodes[0];
7638 uniqueNodes[1] = curNodes[1];
7639 uniqueNodes[2] = curNodes[2];
7640 uniqueNodes[3] = curNodes[4];
7641 uniqueNodes[4] = curNodes[5];
7642 uniqueNodes[5] = curNodes[7];
7645 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7646 uniqueNodes[0] = curNodes[0];
7647 uniqueNodes[1] = curNodes[1];
7648 uniqueNodes[2] = curNodes[3];
7649 uniqueNodes[3] = curNodes[4];
7650 uniqueNodes[4] = curNodes[2];
7651 uniqueNodes[5] = curNodes[7];
7654 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7655 uniqueNodes[0] = curNodes[0];
7656 uniqueNodes[1] = curNodes[1];
7657 uniqueNodes[2] = curNodes[2];
7658 uniqueNodes[3] = curNodes[4];
7659 uniqueNodes[4] = curNodes[5];
7660 uniqueNodes[5] = curNodes[3];
7665 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7668 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7672 //////////////////////////////////// HEXAHEDRON
7674 SMDS_VolumeTool hexa (elem);
7675 hexa.SetExternalNormal();
7676 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7677 //////////////////////// ---> tetrahedron
7678 for ( int iFace = 0; iFace < 6; iFace++ ) {
7679 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7680 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7681 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7682 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7683 // one face turns into a point ...
7684 int iOppFace = hexa.GetOppFaceIndex( iFace );
7685 ind = hexa.GetFaceNodesIndices( iOppFace );
7687 iUnique = 2; // reverse a tetrahedron bottom
7688 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7689 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7691 else if ( iUnique >= 0 )
7692 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7694 if ( nbStick == 1 ) {
7695 // ... and the opposite one - into a triangle.
7697 ind = hexa.GetFaceNodesIndices( iFace );
7698 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7705 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7706 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7707 for ( int iFace = 0; iFace < 6; iFace++ ) {
7708 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7709 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7710 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7711 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7712 // one face turns into a point ...
7713 int iOppFace = hexa.GetOppFaceIndex( iFace );
7714 ind = hexa.GetFaceNodesIndices( iOppFace );
7716 iUnique = 2; // reverse a tetrahedron 1 bottom
7717 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7718 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7720 else if ( iUnique >= 0 )
7721 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7723 if ( nbStick == 0 ) {
7724 // ... and the opposite one is a quadrangle
7726 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7727 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7730 SMDS_MeshElement* newElem =
7731 aMesh->AddVolume(curNodes[ind[ 0 ]],
7734 curNodes[indTop[ 0 ]]);
7735 myLastCreatedElems.Append(newElem);
7737 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7744 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7745 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7746 // find indices of quad and tri faces
7747 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7748 for ( iFace = 0; iFace < 6; iFace++ ) {
7749 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7751 for ( iCur = 0; iCur < 4; iCur++ )
7752 nodeSet.insert( curNodes[ind[ iCur ]] );
7753 nbUniqueNodes = nodeSet.size();
7754 if ( nbUniqueNodes == 3 )
7755 iTriFace[ nbTri++ ] = iFace;
7756 else if ( nbUniqueNodes == 4 )
7757 iQuadFace[ nbQuad++ ] = iFace;
7759 if (nbQuad == 2 && nbTri == 4 &&
7760 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7761 // 2 opposite quadrangles stuck with a diagonal;
7762 // sample groups of merged indices: (0-4)(2-6)
7763 // --------------------------------------------> 2 tetrahedrons
7764 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7765 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7766 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7767 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7768 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7769 // stuck with 0-2 diagonal
7777 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7778 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7779 // stuck with 1-3 diagonal
7791 uniqueNodes[ 0 ] = curNodes [ i0 ];
7792 uniqueNodes[ 1 ] = curNodes [ i1d ];
7793 uniqueNodes[ 2 ] = curNodes [ i3d ];
7794 uniqueNodes[ 3 ] = curNodes [ i0t ];
7797 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7801 myLastCreatedElems.Append(newElem);
7803 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7806 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7807 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7808 // --------------------------------------------> prism
7809 // find 2 opposite triangles
7811 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7812 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7813 // find indices of kept and replaced nodes
7814 // and fill unique nodes of 2 opposite triangles
7815 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7816 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7817 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7818 // fill unique nodes
7821 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7822 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7823 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7825 // iCur of a linked node of the opposite face (make normals co-directed):
7826 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7827 // check that correspondent corners of triangles are linked
7828 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7831 uniqueNodes[ iUnique ] = n;
7832 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7841 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7847 } // switch ( nbNodes )
7849 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7852 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7853 // Change nodes of polyedre
7854 const SMDS_VtkVolume* aPolyedre =
7855 dynamic_cast<const SMDS_VtkVolume*>( elem );
7857 int nbFaces = aPolyedre->NbFaces();
7859 vector<const SMDS_MeshNode *> poly_nodes;
7860 vector<int> quantities (nbFaces);
7862 for (int iface = 1; iface <= nbFaces; iface++) {
7863 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7864 quantities[iface - 1] = nbFaceNodes;
7866 for (inode = 1; inode <= nbFaceNodes; inode++) {
7867 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7869 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7870 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7871 curNode = (*nnIt).second;
7873 poly_nodes.push_back(curNode);
7876 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7880 //int elemId = elem->GetID();
7881 //MESSAGE("Change regular element or polygon " << elemId);
7882 SMDSAbs_ElementType etyp = elem->GetType();
7883 uniqueNodes.resize(nbUniqueNodes);
7884 SMDS_MeshElement* newElem = 0;
7885 if (elem->GetEntityType() == SMDSEntity_Polygon)
7886 newElem = this->AddElement(uniqueNodes, etyp, true);
7888 newElem = this->AddElement(uniqueNodes, etyp, false);
7891 myLastCreatedElems.Append(newElem);
7893 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7895 aMesh->RemoveElement(elem);
7899 // Remove invalid regular element or invalid polygon
7900 //MESSAGE("Remove invalid " << elem->GetID());
7901 rmElemIds.push_back( elem->GetID() );
7904 } // loop on elements
7906 // Remove bad elements, then equal nodes (order important)
7908 Remove( rmElemIds, false );
7909 Remove( rmNodeIds, true );
7914 // ========================================================
7915 // class : SortableElement
7916 // purpose : allow sorting elements basing on their nodes
7917 // ========================================================
7918 class SortableElement : public set <const SMDS_MeshElement*>
7922 SortableElement( const SMDS_MeshElement* theElem )
7925 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7926 while ( nodeIt->more() )
7927 this->insert( nodeIt->next() );
7930 const SMDS_MeshElement* Get() const
7933 void Set(const SMDS_MeshElement* e) const
7938 mutable const SMDS_MeshElement* myElem;
7941 //=======================================================================
7942 //function : FindEqualElements
7943 //purpose : Return list of group of elements built on the same nodes.
7944 // Search among theElements or in the whole mesh if theElements is empty
7945 //=======================================================================
7946 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7947 TListOfListOfElementsID & theGroupsOfElementsID)
7949 myLastCreatedElems.Clear();
7950 myLastCreatedNodes.Clear();
7952 typedef set<const SMDS_MeshElement*> TElemsSet;
7953 typedef map< SortableElement, int > TMapOfNodeSet;
7954 typedef list<int> TGroupOfElems;
7957 if ( theElements.empty() )
7958 { // get all elements in the mesh
7959 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7960 while ( eIt->more() )
7961 elems.insert( elems.end(), eIt->next());
7964 elems = theElements;
7966 vector< TGroupOfElems > arrayOfGroups;
7967 TGroupOfElems groupOfElems;
7968 TMapOfNodeSet mapOfNodeSet;
7970 TElemsSet::iterator elemIt = elems.begin();
7971 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7972 const SMDS_MeshElement* curElem = *elemIt;
7973 SortableElement SE(curElem);
7976 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7977 if( !(pp.second) ) {
7978 TMapOfNodeSet::iterator& itSE = pp.first;
7979 ind = (*itSE).second;
7980 arrayOfGroups[ind].push_back(curElem->GetID());
7983 groupOfElems.clear();
7984 groupOfElems.push_back(curElem->GetID());
7985 arrayOfGroups.push_back(groupOfElems);
7990 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7991 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7992 groupOfElems = *groupIt;
7993 if ( groupOfElems.size() > 1 ) {
7994 groupOfElems.sort();
7995 theGroupsOfElementsID.push_back(groupOfElems);
8000 //=======================================================================
8001 //function : MergeElements
8002 //purpose : In each given group, substitute all elements by the first one.
8003 //=======================================================================
8005 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8007 myLastCreatedElems.Clear();
8008 myLastCreatedNodes.Clear();
8010 typedef list<int> TListOfIDs;
8011 TListOfIDs rmElemIds; // IDs of elems to remove
8013 SMESHDS_Mesh* aMesh = GetMeshDS();
8015 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8016 while ( groupsIt != theGroupsOfElementsID.end() ) {
8017 TListOfIDs& aGroupOfElemID = *groupsIt;
8018 aGroupOfElemID.sort();
8019 int elemIDToKeep = aGroupOfElemID.front();
8020 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8021 aGroupOfElemID.pop_front();
8022 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8023 while ( idIt != aGroupOfElemID.end() ) {
8024 int elemIDToRemove = *idIt;
8025 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8026 // add the kept element in groups of removed one (PAL15188)
8027 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8028 rmElemIds.push_back( elemIDToRemove );
8034 Remove( rmElemIds, false );
8037 //=======================================================================
8038 //function : MergeEqualElements
8039 //purpose : Remove all but one of elements built on the same nodes.
8040 //=======================================================================
8042 void SMESH_MeshEditor::MergeEqualElements()
8044 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8045 to merge equal elements in the whole mesh */
8046 TListOfListOfElementsID aGroupsOfElementsID;
8047 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8048 MergeElements(aGroupsOfElementsID);
8051 //=======================================================================
8052 //function : FindFaceInSet
8053 //purpose : Return a face having linked nodes n1 and n2 and which is
8054 // - not in avoidSet,
8055 // - in elemSet provided that !elemSet.empty()
8056 // i1 and i2 optionally returns indices of n1 and n2
8057 //=======================================================================
8059 const SMDS_MeshElement*
8060 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8061 const SMDS_MeshNode* n2,
8062 const TIDSortedElemSet& elemSet,
8063 const TIDSortedElemSet& avoidSet,
8069 const SMDS_MeshElement* face = 0;
8071 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8072 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8073 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8075 //MESSAGE("in while ( invElemIt->more() && !face )");
8076 const SMDS_MeshElement* elem = invElemIt->next();
8077 if (avoidSet.count( elem ))
8079 if ( !elemSet.empty() && !elemSet.count( elem ))
8082 i1 = elem->GetNodeIndex( n1 );
8083 // find a n2 linked to n1
8084 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8085 for ( int di = -1; di < 2 && !face; di += 2 )
8087 i2 = (i1+di+nbN) % nbN;
8088 if ( elem->GetNode( i2 ) == n2 )
8091 if ( !face && elem->IsQuadratic())
8093 // analysis for quadratic elements using all nodes
8094 const SMDS_VtkFace* F =
8095 dynamic_cast<const SMDS_VtkFace*>(elem);
8096 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8097 // use special nodes iterator
8098 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8099 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8100 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8102 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8103 if ( n1 == prevN && n2 == n )
8107 else if ( n2 == prevN && n1 == n )
8109 face = elem; swap( i1, i2 );
8115 if ( n1ind ) *n1ind = i1;
8116 if ( n2ind ) *n2ind = i2;
8120 //=======================================================================
8121 //function : findAdjacentFace
8123 //=======================================================================
8125 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8126 const SMDS_MeshNode* n2,
8127 const SMDS_MeshElement* elem)
8129 TIDSortedElemSet elemSet, avoidSet;
8131 avoidSet.insert ( elem );
8132 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8135 //=======================================================================
8136 //function : FindFreeBorder
8138 //=======================================================================
8140 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8142 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8143 const SMDS_MeshNode* theSecondNode,
8144 const SMDS_MeshNode* theLastNode,
8145 list< const SMDS_MeshNode* > & theNodes,
8146 list< const SMDS_MeshElement* >& theFaces)
8148 if ( !theFirstNode || !theSecondNode )
8150 // find border face between theFirstNode and theSecondNode
8151 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8155 theFaces.push_back( curElem );
8156 theNodes.push_back( theFirstNode );
8157 theNodes.push_back( theSecondNode );
8159 //vector<const SMDS_MeshNode*> nodes;
8160 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8161 TIDSortedElemSet foundElems;
8162 bool needTheLast = ( theLastNode != 0 );
8164 while ( nStart != theLastNode ) {
8165 if ( nStart == theFirstNode )
8166 return !needTheLast;
8168 // find all free border faces sharing form nStart
8170 list< const SMDS_MeshElement* > curElemList;
8171 list< const SMDS_MeshNode* > nStartList;
8172 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8173 while ( invElemIt->more() ) {
8174 const SMDS_MeshElement* e = invElemIt->next();
8175 if ( e == curElem || foundElems.insert( e ).second ) {
8177 int iNode = 0, nbNodes = e->NbNodes();
8178 //const SMDS_MeshNode* nodes[nbNodes+1];
8179 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8181 if(e->IsQuadratic()) {
8182 const SMDS_VtkFace* F =
8183 dynamic_cast<const SMDS_VtkFace*>(e);
8184 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8185 // use special nodes iterator
8186 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8187 while( anIter->more() ) {
8188 nodes[ iNode++ ] = cast2Node(anIter->next());
8192 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8193 while ( nIt->more() )
8194 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8196 nodes[ iNode ] = nodes[ 0 ];
8198 for ( iNode = 0; iNode < nbNodes; iNode++ )
8199 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8200 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8201 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8203 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8204 curElemList.push_back( e );
8208 // analyse the found
8210 int nbNewBorders = curElemList.size();
8211 if ( nbNewBorders == 0 ) {
8212 // no free border furthermore
8213 return !needTheLast;
8215 else if ( nbNewBorders == 1 ) {
8216 // one more element found
8218 nStart = nStartList.front();
8219 curElem = curElemList.front();
8220 theFaces.push_back( curElem );
8221 theNodes.push_back( nStart );
8224 // several continuations found
8225 list< const SMDS_MeshElement* >::iterator curElemIt;
8226 list< const SMDS_MeshNode* >::iterator nStartIt;
8227 // check if one of them reached the last node
8228 if ( needTheLast ) {
8229 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8230 curElemIt!= curElemList.end();
8231 curElemIt++, nStartIt++ )
8232 if ( *nStartIt == theLastNode ) {
8233 theFaces.push_back( *curElemIt );
8234 theNodes.push_back( *nStartIt );
8238 // find the best free border by the continuations
8239 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8240 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8241 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8242 curElemIt!= curElemList.end();
8243 curElemIt++, nStartIt++ )
8245 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8246 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8247 // find one more free border
8248 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8252 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8253 // choice: clear a worse one
8254 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8255 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8256 contNodes[ iWorse ].clear();
8257 contFaces[ iWorse ].clear();
8260 if ( contNodes[0].empty() && contNodes[1].empty() )
8263 // append the best free border
8264 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8265 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8266 theNodes.pop_back(); // remove nIgnore
8267 theNodes.pop_back(); // remove nStart
8268 theFaces.pop_back(); // remove curElem
8269 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8270 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8271 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8272 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8275 } // several continuations found
8276 } // while ( nStart != theLastNode )
8281 //=======================================================================
8282 //function : CheckFreeBorderNodes
8283 //purpose : Return true if the tree nodes are on a free border
8284 //=======================================================================
8286 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8287 const SMDS_MeshNode* theNode2,
8288 const SMDS_MeshNode* theNode3)
8290 list< const SMDS_MeshNode* > nodes;
8291 list< const SMDS_MeshElement* > faces;
8292 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8295 //=======================================================================
8296 //function : SewFreeBorder
8298 //=======================================================================
8300 SMESH_MeshEditor::Sew_Error
8301 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8302 const SMDS_MeshNode* theBordSecondNode,
8303 const SMDS_MeshNode* theBordLastNode,
8304 const SMDS_MeshNode* theSideFirstNode,
8305 const SMDS_MeshNode* theSideSecondNode,
8306 const SMDS_MeshNode* theSideThirdNode,
8307 const bool theSideIsFreeBorder,
8308 const bool toCreatePolygons,
8309 const bool toCreatePolyedrs)
8311 myLastCreatedElems.Clear();
8312 myLastCreatedNodes.Clear();
8314 MESSAGE("::SewFreeBorder()");
8315 Sew_Error aResult = SEW_OK;
8317 // ====================================
8318 // find side nodes and elements
8319 // ====================================
8321 list< const SMDS_MeshNode* > nSide[ 2 ];
8322 list< const SMDS_MeshElement* > eSide[ 2 ];
8323 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8324 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8328 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8329 nSide[0], eSide[0])) {
8330 MESSAGE(" Free Border 1 not found " );
8331 aResult = SEW_BORDER1_NOT_FOUND;
8333 if (theSideIsFreeBorder) {
8336 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8337 nSide[1], eSide[1])) {
8338 MESSAGE(" Free Border 2 not found " );
8339 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8342 if ( aResult != SEW_OK )
8345 if (!theSideIsFreeBorder) {
8349 // -------------------------------------------------------------------------
8351 // 1. If nodes to merge are not coincident, move nodes of the free border
8352 // from the coord sys defined by the direction from the first to last
8353 // nodes of the border to the correspondent sys of the side 2
8354 // 2. On the side 2, find the links most co-directed with the correspondent
8355 // links of the free border
8356 // -------------------------------------------------------------------------
8358 // 1. Since sewing may break if there are volumes to split on the side 2,
8359 // we wont move nodes but just compute new coordinates for them
8360 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8361 TNodeXYZMap nBordXYZ;
8362 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8363 list< const SMDS_MeshNode* >::iterator nBordIt;
8365 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8366 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8367 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8368 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8369 double tol2 = 1.e-8;
8370 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8371 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8372 // Need node movement.
8374 // find X and Z axes to create trsf
8375 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8377 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8379 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8382 gp_Ax3 toBordAx( Pb1, Zb, X );
8383 gp_Ax3 fromSideAx( Ps1, Zs, X );
8384 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8386 gp_Trsf toBordSys, fromSide2Sys;
8387 toBordSys.SetTransformation( toBordAx );
8388 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8389 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8392 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8393 const SMDS_MeshNode* n = *nBordIt;
8394 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8395 toBordSys.Transforms( xyz );
8396 fromSide2Sys.Transforms( xyz );
8397 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8401 // just insert nodes XYZ in the nBordXYZ map
8402 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8403 const SMDS_MeshNode* n = *nBordIt;
8404 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8408 // 2. On the side 2, find the links most co-directed with the correspondent
8409 // links of the free border
8411 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8412 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8413 sideNodes.push_back( theSideFirstNode );
8415 bool hasVolumes = false;
8416 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8417 set<long> foundSideLinkIDs, checkedLinkIDs;
8418 SMDS_VolumeTool volume;
8419 //const SMDS_MeshNode* faceNodes[ 4 ];
8421 const SMDS_MeshNode* sideNode;
8422 const SMDS_MeshElement* sideElem;
8423 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8424 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8425 nBordIt = bordNodes.begin();
8427 // border node position and border link direction to compare with
8428 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8429 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8430 // choose next side node by link direction or by closeness to
8431 // the current border node:
8432 bool searchByDir = ( *nBordIt != theBordLastNode );
8434 // find the next node on the Side 2
8436 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8438 checkedLinkIDs.clear();
8439 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8441 // loop on inverse elements of current node (prevSideNode) on the Side 2
8442 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8443 while ( invElemIt->more() )
8445 const SMDS_MeshElement* elem = invElemIt->next();
8446 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8447 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8448 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8449 bool isVolume = volume.Set( elem );
8450 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8451 if ( isVolume ) // --volume
8453 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8454 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8455 if(elem->IsQuadratic()) {
8456 const SMDS_VtkFace* F =
8457 dynamic_cast<const SMDS_VtkFace*>(elem);
8458 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8459 // use special nodes iterator
8460 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8461 while( anIter->more() ) {
8462 nodes[ iNode ] = cast2Node(anIter->next());
8463 if ( nodes[ iNode++ ] == prevSideNode )
8464 iPrevNode = iNode - 1;
8468 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8469 while ( nIt->more() ) {
8470 nodes[ iNode ] = cast2Node( nIt->next() );
8471 if ( nodes[ iNode++ ] == prevSideNode )
8472 iPrevNode = iNode - 1;
8475 // there are 2 links to check
8480 // loop on links, to be precise, on the second node of links
8481 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8482 const SMDS_MeshNode* n = nodes[ iNode ];
8484 if ( !volume.IsLinked( n, prevSideNode ))
8488 if ( iNode ) // a node before prevSideNode
8489 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8490 else // a node after prevSideNode
8491 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8493 // check if this link was already used
8494 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8495 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8496 if (!isJustChecked &&
8497 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8499 // test a link geometrically
8500 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8501 bool linkIsBetter = false;
8502 double dot = 0.0, dist = 0.0;
8503 if ( searchByDir ) { // choose most co-directed link
8504 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8505 linkIsBetter = ( dot > maxDot );
8507 else { // choose link with the node closest to bordPos
8508 dist = ( nextXYZ - bordPos ).SquareModulus();
8509 linkIsBetter = ( dist < minDist );
8511 if ( linkIsBetter ) {
8520 } // loop on inverse elements of prevSideNode
8523 MESSAGE(" Cant find path by links of the Side 2 ");
8524 return SEW_BAD_SIDE_NODES;
8526 sideNodes.push_back( sideNode );
8527 sideElems.push_back( sideElem );
8528 foundSideLinkIDs.insert ( linkID );
8529 prevSideNode = sideNode;
8531 if ( *nBordIt == theBordLastNode )
8532 searchByDir = false;
8534 // find the next border link to compare with
8535 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8536 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8537 // move to next border node if sideNode is before forward border node (bordPos)
8538 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8539 prevBordNode = *nBordIt;
8541 bordPos = nBordXYZ[ *nBordIt ];
8542 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8543 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8547 while ( sideNode != theSideSecondNode );
8549 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8550 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8551 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8553 } // end nodes search on the side 2
8555 // ============================
8556 // sew the border to the side 2
8557 // ============================
8559 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8560 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8562 TListOfListOfNodes nodeGroupsToMerge;
8563 if ( nbNodes[0] == nbNodes[1] ||
8564 ( theSideIsFreeBorder && !theSideThirdNode)) {
8566 // all nodes are to be merged
8568 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8569 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8570 nIt[0]++, nIt[1]++ )
8572 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8573 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8574 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8579 // insert new nodes into the border and the side to get equal nb of segments
8581 // get normalized parameters of nodes on the borders
8582 //double param[ 2 ][ maxNbNodes ];
8584 param[0] = new double [ maxNbNodes ];
8585 param[1] = new double [ maxNbNodes ];
8587 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8588 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8589 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8590 const SMDS_MeshNode* nPrev = *nIt;
8591 double bordLength = 0;
8592 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8593 const SMDS_MeshNode* nCur = *nIt;
8594 gp_XYZ segment (nCur->X() - nPrev->X(),
8595 nCur->Y() - nPrev->Y(),
8596 nCur->Z() - nPrev->Z());
8597 double segmentLen = segment.Modulus();
8598 bordLength += segmentLen;
8599 param[ iBord ][ iNode ] = bordLength;
8602 // normalize within [0,1]
8603 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8604 param[ iBord ][ iNode ] /= bordLength;
8608 // loop on border segments
8609 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8610 int i[ 2 ] = { 0, 0 };
8611 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8612 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8614 TElemOfNodeListMap insertMap;
8615 TElemOfNodeListMap::iterator insertMapIt;
8617 // key: elem to insert nodes into
8618 // value: 2 nodes to insert between + nodes to be inserted
8620 bool next[ 2 ] = { false, false };
8622 // find min adjacent segment length after sewing
8623 double nextParam = 10., prevParam = 0;
8624 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8625 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8626 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8627 if ( i[ iBord ] > 0 )
8628 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8630 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8631 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8632 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8634 // choose to insert or to merge nodes
8635 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8636 if ( Abs( du ) <= minSegLen * 0.2 ) {
8639 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8640 const SMDS_MeshNode* n0 = *nIt[0];
8641 const SMDS_MeshNode* n1 = *nIt[1];
8642 nodeGroupsToMerge.back().push_back( n1 );
8643 nodeGroupsToMerge.back().push_back( n0 );
8644 // position of node of the border changes due to merge
8645 param[ 0 ][ i[0] ] += du;
8646 // move n1 for the sake of elem shape evaluation during insertion.
8647 // n1 will be removed by MergeNodes() anyway
8648 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8649 next[0] = next[1] = true;
8654 int intoBord = ( du < 0 ) ? 0 : 1;
8655 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8656 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8657 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8658 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8659 if ( intoBord == 1 ) {
8660 // move node of the border to be on a link of elem of the side
8661 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8662 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8663 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8664 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8665 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8667 insertMapIt = insertMap.find( elem );
8668 bool notFound = ( insertMapIt == insertMap.end() );
8669 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8671 // insert into another link of the same element:
8672 // 1. perform insertion into the other link of the elem
8673 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8674 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8675 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8676 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8677 // 2. perform insertion into the link of adjacent faces
8679 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8681 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8685 if (toCreatePolyedrs) {
8686 // perform insertion into the links of adjacent volumes
8687 UpdateVolumes(n12, n22, nodeList);
8689 // 3. find an element appeared on n1 and n2 after the insertion
8690 insertMap.erase( elem );
8691 elem = findAdjacentFace( n1, n2, 0 );
8693 if ( notFound || otherLink ) {
8694 // add element and nodes of the side into the insertMap
8695 insertMapIt = insertMap.insert
8696 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8697 (*insertMapIt).second.push_back( n1 );
8698 (*insertMapIt).second.push_back( n2 );
8700 // add node to be inserted into elem
8701 (*insertMapIt).second.push_back( nIns );
8702 next[ 1 - intoBord ] = true;
8705 // go to the next segment
8706 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8707 if ( next[ iBord ] ) {
8708 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8710 nPrev[ iBord ] = *nIt[ iBord ];
8711 nIt[ iBord ]++; i[ iBord ]++;
8715 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8717 // perform insertion of nodes into elements
8719 for (insertMapIt = insertMap.begin();
8720 insertMapIt != insertMap.end();
8723 const SMDS_MeshElement* elem = (*insertMapIt).first;
8724 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8725 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8726 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8728 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8730 if ( !theSideIsFreeBorder ) {
8731 // look for and insert nodes into the faces adjacent to elem
8733 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8735 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8740 if (toCreatePolyedrs) {
8741 // perform insertion into the links of adjacent volumes
8742 UpdateVolumes(n1, n2, nodeList);
8748 } // end: insert new nodes
8750 MergeNodes ( nodeGroupsToMerge );
8755 //=======================================================================
8756 //function : InsertNodesIntoLink
8757 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8758 // and theBetweenNode2 and split theElement
8759 //=======================================================================
8761 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8762 const SMDS_MeshNode* theBetweenNode1,
8763 const SMDS_MeshNode* theBetweenNode2,
8764 list<const SMDS_MeshNode*>& theNodesToInsert,
8765 const bool toCreatePoly)
8767 if ( theFace->GetType() != SMDSAbs_Face ) return;
8769 // find indices of 2 link nodes and of the rest nodes
8770 int iNode = 0, il1, il2, i3, i4;
8771 il1 = il2 = i3 = i4 = -1;
8772 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8773 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8775 if(theFace->IsQuadratic()) {
8776 const SMDS_VtkFace* F =
8777 dynamic_cast<const SMDS_VtkFace*>(theFace);
8778 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8779 // use special nodes iterator
8780 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8781 while( anIter->more() ) {
8782 const SMDS_MeshNode* n = cast2Node(anIter->next());
8783 if ( n == theBetweenNode1 )
8785 else if ( n == theBetweenNode2 )
8791 nodes[ iNode++ ] = n;
8795 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8796 while ( nodeIt->more() ) {
8797 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8798 if ( n == theBetweenNode1 )
8800 else if ( n == theBetweenNode2 )
8806 nodes[ iNode++ ] = n;
8809 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8812 // arrange link nodes to go one after another regarding the face orientation
8813 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8814 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8819 aNodesToInsert.reverse();
8821 // check that not link nodes of a quadrangles are in good order
8822 int nbFaceNodes = theFace->NbNodes();
8823 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8829 if (toCreatePoly || theFace->IsPoly()) {
8832 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8834 // add nodes of face up to first node of link
8837 if(theFace->IsQuadratic()) {
8838 const SMDS_VtkFace* F =
8839 dynamic_cast<const SMDS_VtkFace*>(theFace);
8840 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8841 // use special nodes iterator
8842 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8843 while( anIter->more() && !isFLN ) {
8844 const SMDS_MeshNode* n = cast2Node(anIter->next());
8845 poly_nodes[iNode++] = n;
8846 if (n == nodes[il1]) {
8850 // add nodes to insert
8851 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8852 for (; nIt != aNodesToInsert.end(); nIt++) {
8853 poly_nodes[iNode++] = *nIt;
8855 // add nodes of face starting from last node of link
8856 while ( anIter->more() ) {
8857 poly_nodes[iNode++] = cast2Node(anIter->next());
8861 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8862 while ( nodeIt->more() && !isFLN ) {
8863 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8864 poly_nodes[iNode++] = n;
8865 if (n == nodes[il1]) {
8869 // add nodes to insert
8870 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8871 for (; nIt != aNodesToInsert.end(); nIt++) {
8872 poly_nodes[iNode++] = *nIt;
8874 // add nodes of face starting from last node of link
8875 while ( nodeIt->more() ) {
8876 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8877 poly_nodes[iNode++] = n;
8881 // edit or replace the face
8882 SMESHDS_Mesh *aMesh = GetMeshDS();
8884 if (theFace->IsPoly()) {
8885 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8888 int aShapeId = FindShape( theFace );
8890 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8891 myLastCreatedElems.Append(newElem);
8892 if ( aShapeId && newElem )
8893 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8895 aMesh->RemoveElement(theFace);
8900 SMESHDS_Mesh *aMesh = GetMeshDS();
8901 if( !theFace->IsQuadratic() ) {
8903 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8904 int nbLinkNodes = 2 + aNodesToInsert.size();
8905 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8906 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8907 linkNodes[ 0 ] = nodes[ il1 ];
8908 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8909 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8910 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8911 linkNodes[ iNode++ ] = *nIt;
8913 // decide how to split a quadrangle: compare possible variants
8914 // and choose which of splits to be a quadrangle
8915 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8916 if ( nbFaceNodes == 3 ) {
8917 iBestQuad = nbSplits;
8920 else if ( nbFaceNodes == 4 ) {
8921 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8922 double aBestRate = DBL_MAX;
8923 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8925 double aBadRate = 0;
8926 // evaluate elements quality
8927 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8928 if ( iSplit == iQuad ) {
8929 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8933 aBadRate += getBadRate( &quad, aCrit );
8936 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8938 nodes[ iSplit < iQuad ? i4 : i3 ]);
8939 aBadRate += getBadRate( &tria, aCrit );
8943 if ( aBadRate < aBestRate ) {
8945 aBestRate = aBadRate;
8950 // create new elements
8951 int aShapeId = FindShape( theFace );
8954 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8955 SMDS_MeshElement* newElem = 0;
8956 if ( iSplit == iBestQuad )
8957 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8962 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8964 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8965 myLastCreatedElems.Append(newElem);
8966 if ( aShapeId && newElem )
8967 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8970 // change nodes of theFace
8971 const SMDS_MeshNode* newNodes[ 4 ];
8972 newNodes[ 0 ] = linkNodes[ i1 ];
8973 newNodes[ 1 ] = linkNodes[ i2 ];
8974 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8975 newNodes[ 3 ] = nodes[ i4 ];
8976 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8977 const SMDS_MeshElement* newElem = 0;
8978 if (iSplit == iBestQuad)
8979 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8981 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8982 myLastCreatedElems.Append(newElem);
8983 if ( aShapeId && newElem )
8984 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8985 } // end if(!theFace->IsQuadratic())
8986 else { // theFace is quadratic
8987 // we have to split theFace on simple triangles and one simple quadrangle
8989 int nbshift = tmp*2;
8990 // shift nodes in nodes[] by nbshift
8992 for(i=0; i<nbshift; i++) {
8993 const SMDS_MeshNode* n = nodes[0];
8994 for(j=0; j<nbFaceNodes-1; j++) {
8995 nodes[j] = nodes[j+1];
8997 nodes[nbFaceNodes-1] = n;
8999 il1 = il1 - nbshift;
9000 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9001 // n0 n1 n2 n0 n1 n2
9002 // +-----+-----+ +-----+-----+
9011 // create new elements
9012 int aShapeId = FindShape( theFace );
9015 if(nbFaceNodes==6) { // quadratic triangle
9016 SMDS_MeshElement* newElem =
9017 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9018 myLastCreatedElems.Append(newElem);
9019 if ( aShapeId && newElem )
9020 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9021 if(theFace->IsMediumNode(nodes[il1])) {
9022 // create quadrangle
9023 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9024 myLastCreatedElems.Append(newElem);
9025 if ( aShapeId && newElem )
9026 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9032 // create quadrangle
9033 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9034 myLastCreatedElems.Append(newElem);
9035 if ( aShapeId && newElem )
9036 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9042 else { // nbFaceNodes==8 - quadratic quadrangle
9043 SMDS_MeshElement* newElem =
9044 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9045 myLastCreatedElems.Append(newElem);
9046 if ( aShapeId && newElem )
9047 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9048 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9049 myLastCreatedElems.Append(newElem);
9050 if ( aShapeId && newElem )
9051 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9052 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9053 myLastCreatedElems.Append(newElem);
9054 if ( aShapeId && newElem )
9055 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9056 if(theFace->IsMediumNode(nodes[il1])) {
9057 // create quadrangle
9058 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9059 myLastCreatedElems.Append(newElem);
9060 if ( aShapeId && newElem )
9061 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9067 // create quadrangle
9068 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9069 myLastCreatedElems.Append(newElem);
9070 if ( aShapeId && newElem )
9071 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9077 // create needed triangles using n1,n2,n3 and inserted nodes
9078 int nbn = 2 + aNodesToInsert.size();
9079 //const SMDS_MeshNode* aNodes[nbn];
9080 vector<const SMDS_MeshNode*> aNodes(nbn);
9081 aNodes[0] = nodes[n1];
9082 aNodes[nbn-1] = nodes[n2];
9083 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9084 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9085 aNodes[iNode++] = *nIt;
9087 for(i=1; i<nbn; i++) {
9088 SMDS_MeshElement* newElem =
9089 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9090 myLastCreatedElems.Append(newElem);
9091 if ( aShapeId && newElem )
9092 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9096 aMesh->RemoveElement(theFace);
9099 //=======================================================================
9100 //function : UpdateVolumes
9102 //=======================================================================
9103 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9104 const SMDS_MeshNode* theBetweenNode2,
9105 list<const SMDS_MeshNode*>& theNodesToInsert)
9107 myLastCreatedElems.Clear();
9108 myLastCreatedNodes.Clear();
9110 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9111 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9112 const SMDS_MeshElement* elem = invElemIt->next();
9114 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9115 SMDS_VolumeTool aVolume (elem);
9116 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9119 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9120 int iface, nbFaces = aVolume.NbFaces();
9121 vector<const SMDS_MeshNode *> poly_nodes;
9122 vector<int> quantities (nbFaces);
9124 for (iface = 0; iface < nbFaces; iface++) {
9125 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9126 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9127 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9129 for (int inode = 0; inode < nbFaceNodes; inode++) {
9130 poly_nodes.push_back(faceNodes[inode]);
9132 if (nbInserted == 0) {
9133 if (faceNodes[inode] == theBetweenNode1) {
9134 if (faceNodes[inode + 1] == theBetweenNode2) {
9135 nbInserted = theNodesToInsert.size();
9137 // add nodes to insert
9138 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9139 for (; nIt != theNodesToInsert.end(); nIt++) {
9140 poly_nodes.push_back(*nIt);
9144 else if (faceNodes[inode] == theBetweenNode2) {
9145 if (faceNodes[inode + 1] == theBetweenNode1) {
9146 nbInserted = theNodesToInsert.size();
9148 // add nodes to insert in reversed order
9149 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9151 for (; nIt != theNodesToInsert.begin(); nIt--) {
9152 poly_nodes.push_back(*nIt);
9154 poly_nodes.push_back(*nIt);
9161 quantities[iface] = nbFaceNodes + nbInserted;
9164 // Replace or update the volume
9165 SMESHDS_Mesh *aMesh = GetMeshDS();
9167 if (elem->IsPoly()) {
9168 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9172 int aShapeId = FindShape( elem );
9174 SMDS_MeshElement* newElem =
9175 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9176 myLastCreatedElems.Append(newElem);
9177 if (aShapeId && newElem)
9178 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9180 aMesh->RemoveElement(elem);
9185 //=======================================================================
9187 * \brief Convert elements contained in a submesh to quadratic
9188 * \return int - nb of checked elements
9190 //=======================================================================
9192 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9193 SMESH_MesherHelper& theHelper,
9194 const bool theForce3d)
9197 if( !theSm ) return nbElem;
9199 vector<int> nbNodeInFaces;
9200 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9201 while(ElemItr->more())
9204 const SMDS_MeshElement* elem = ElemItr->next();
9205 if( !elem || elem->IsQuadratic() ) continue;
9207 int id = elem->GetID();
9208 int nbNodes = elem->NbNodes();
9209 SMDSAbs_ElementType aType = elem->GetType();
9211 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9212 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9213 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9215 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9217 const SMDS_MeshElement* NewElem = 0;
9223 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9231 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9234 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9237 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9242 case SMDSAbs_Volume :
9247 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9250 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9253 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9256 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9257 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9260 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9267 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9269 theSm->AddElement( NewElem );
9271 // if (!GetMeshDS()->isCompacted())
9272 // GetMeshDS()->compactMesh();
9276 //=======================================================================
9277 //function : ConvertToQuadratic
9279 //=======================================================================
9280 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9282 SMESHDS_Mesh* meshDS = GetMeshDS();
9284 SMESH_MesherHelper aHelper(*myMesh);
9285 aHelper.SetIsQuadratic( true );
9287 int nbCheckedElems = 0;
9288 if ( myMesh->HasShapeToMesh() )
9290 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9292 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9293 while ( smIt->more() ) {
9294 SMESH_subMesh* sm = smIt->next();
9295 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9296 aHelper.SetSubShape( sm->GetSubShape() );
9297 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9302 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9303 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9305 SMESHDS_SubMesh *smDS = 0;
9306 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9307 while(aEdgeItr->more())
9309 const SMDS_MeshEdge* edge = aEdgeItr->next();
9310 if(edge && !edge->IsQuadratic())
9312 int id = edge->GetID();
9313 //MESSAGE("edge->GetID() " << id);
9314 const SMDS_MeshNode* n1 = edge->GetNode(0);
9315 const SMDS_MeshNode* n2 = edge->GetNode(1);
9317 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9319 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9320 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9323 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9324 while(aFaceItr->more())
9326 const SMDS_MeshFace* face = aFaceItr->next();
9327 if(!face || face->IsQuadratic() ) continue;
9329 int id = face->GetID();
9330 int nbNodes = face->NbNodes();
9331 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9333 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9335 SMDS_MeshFace * NewFace = 0;
9339 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9342 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9345 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9347 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9349 vector<int> nbNodeInFaces;
9350 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9351 while(aVolumeItr->more())
9353 const SMDS_MeshVolume* volume = aVolumeItr->next();
9354 if(!volume || volume->IsQuadratic() ) continue;
9356 int id = volume->GetID();
9357 int nbNodes = volume->NbNodes();
9358 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9359 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9360 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9362 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9364 SMDS_MeshVolume * NewVolume = 0;
9368 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9369 nodes[3], id, theForce3d );
9372 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9373 nodes[3], nodes[4], id, theForce3d);
9376 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9377 nodes[3], nodes[4], nodes[5], id, theForce3d);
9380 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9381 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9384 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9386 ReplaceElemInGroups(volume, NewVolume, meshDS);
9390 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9391 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9392 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9393 aHelper.FixQuadraticElements();
9397 //================================================================================
9399 * \brief Makes given elements quadratic
9400 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9401 * \param theElements - elements to make quadratic
9403 //================================================================================
9405 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9406 TIDSortedElemSet& theElements)
9408 if ( theElements.empty() ) return;
9410 // we believe that all theElements are of the same type
9411 SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9413 // get all nodes shared by theElements
9414 TIDSortedNodeSet allNodes;
9415 TIDSortedElemSet::iterator eIt = theElements.begin();
9416 for ( ; eIt != theElements.end(); ++eIt )
9417 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9419 // complete theElements with elements of lower dim whose all nodes are in allNodes
9421 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9422 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9423 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9424 for ( ; nIt != allNodes.end(); ++nIt )
9426 const SMDS_MeshNode* n = *nIt;
9427 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9428 while ( invIt->more() )
9430 const SMDS_MeshElement* e = invIt->next();
9431 if ( e->IsQuadratic() )
9433 quadAdjacentElems[ e->GetType() ].insert( e );
9436 if ( e->GetType() >= elemType )
9438 continue; // same type of more complex linear element
9441 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9442 continue; // e is already checked
9446 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9447 while ( nodeIt->more() && allIn )
9448 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9450 theElements.insert(e );
9454 SMESH_MesherHelper helper(*myMesh);
9455 helper.SetIsQuadratic( true );
9457 // add links of quadratic adjacent elements to the helper
9459 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9460 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9461 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9463 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9465 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9466 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9467 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9469 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9471 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9472 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9473 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9475 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9478 // make quadratic elements instead of linear ones
9480 SMESHDS_Mesh* meshDS = GetMeshDS();
9481 SMESHDS_SubMesh* smDS = 0;
9482 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9484 const SMDS_MeshElement* elem = *eIt;
9485 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9488 int id = elem->GetID();
9489 SMDSAbs_ElementType type = elem->GetType();
9490 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9492 if ( !smDS || !smDS->Contains( elem ))
9493 smDS = meshDS->MeshElements( elem->getshapeId() );
9494 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9496 SMDS_MeshElement * newElem = 0;
9497 switch( nodes.size() )
9499 case 4: // cases for most multiple element types go first (for optimization)
9500 if ( type == SMDSAbs_Volume )
9501 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9503 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9506 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9507 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9510 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9513 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9516 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9517 nodes[4], id, theForce3d);
9520 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9521 nodes[4], nodes[5], id, theForce3d);
9525 ReplaceElemInGroups( elem, newElem, meshDS);
9526 if( newElem && smDS )
9527 smDS->AddElement( newElem );
9530 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9531 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9532 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9533 helper.FixQuadraticElements();
9537 //=======================================================================
9539 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9540 * \return int - nb of checked elements
9542 //=======================================================================
9544 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9545 SMDS_ElemIteratorPtr theItr,
9546 const int theShapeID)
9549 SMESHDS_Mesh* meshDS = GetMeshDS();
9551 while( theItr->more() )
9553 const SMDS_MeshElement* elem = theItr->next();
9555 if( elem && elem->IsQuadratic())
9557 int id = elem->GetID();
9558 int nbCornerNodes = elem->NbCornerNodes();
9559 SMDSAbs_ElementType aType = elem->GetType();
9561 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9563 //remove a quadratic element
9564 if ( !theSm || !theSm->Contains( elem ))
9565 theSm = meshDS->MeshElements( elem->getshapeId() );
9566 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9568 // remove medium nodes
9569 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9570 if ( nodes[i]->NbInverseElements() == 0 )
9571 meshDS->RemoveFreeNode( nodes[i], theSm );
9573 // add a linear element
9574 nodes.resize( nbCornerNodes );
9575 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9576 ReplaceElemInGroups(elem, newElem, meshDS);
9577 if( theSm && newElem )
9578 theSm->AddElement( newElem );
9584 //=======================================================================
9585 //function : ConvertFromQuadratic
9587 //=======================================================================
9589 bool SMESH_MeshEditor::ConvertFromQuadratic()
9591 int nbCheckedElems = 0;
9592 if ( myMesh->HasShapeToMesh() )
9594 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9596 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9597 while ( smIt->more() ) {
9598 SMESH_subMesh* sm = smIt->next();
9599 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9600 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9606 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9607 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9609 SMESHDS_SubMesh *aSM = 0;
9610 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9618 //================================================================================
9620 * \brief Return true if all medium nodes of the element are in the node set
9622 //================================================================================
9624 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9626 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9627 if ( !nodeSet.count( elem->GetNode(i) ))
9633 //================================================================================
9635 * \brief Makes given elements linear
9637 //================================================================================
9639 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9641 if ( theElements.empty() ) return;
9643 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9644 set<int> mediumNodeIDs;
9645 TIDSortedElemSet::iterator eIt = theElements.begin();
9646 for ( ; eIt != theElements.end(); ++eIt )
9648 const SMDS_MeshElement* e = *eIt;
9649 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9650 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9653 // replace given elements by linear ones
9654 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9655 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9656 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9658 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9659 // except those elements sharing medium nodes of quadratic element whose medium nodes
9660 // are not all in mediumNodeIDs
9662 // get remaining medium nodes
9663 TIDSortedNodeSet mediumNodes;
9664 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9665 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9666 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9667 mediumNodes.insert( mediumNodes.end(), n );
9669 // find more quadratic elements to convert
9670 TIDSortedElemSet moreElemsToConvert;
9671 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9672 for ( ; nIt != mediumNodes.end(); ++nIt )
9674 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9675 while ( invIt->more() )
9677 const SMDS_MeshElement* e = invIt->next();
9678 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9680 // find a more complex element including e and
9681 // whose medium nodes are not in mediumNodes
9682 bool complexFound = false;
9683 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9685 SMDS_ElemIteratorPtr invIt2 =
9686 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9687 while ( invIt2->more() )
9689 const SMDS_MeshElement* eComplex = invIt2->next();
9690 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9692 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9693 if ( nbCommonNodes == e->NbNodes())
9695 complexFound = true;
9696 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9702 if ( !complexFound )
9703 moreElemsToConvert.insert( e );
9707 elemIt = SMDS_ElemIteratorPtr
9708 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9709 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9712 //=======================================================================
9713 //function : SewSideElements
9715 //=======================================================================
9717 SMESH_MeshEditor::Sew_Error
9718 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9719 TIDSortedElemSet& theSide2,
9720 const SMDS_MeshNode* theFirstNode1,
9721 const SMDS_MeshNode* theFirstNode2,
9722 const SMDS_MeshNode* theSecondNode1,
9723 const SMDS_MeshNode* theSecondNode2)
9725 myLastCreatedElems.Clear();
9726 myLastCreatedNodes.Clear();
9728 MESSAGE ("::::SewSideElements()");
9729 if ( theSide1.size() != theSide2.size() )
9730 return SEW_DIFF_NB_OF_ELEMENTS;
9732 Sew_Error aResult = SEW_OK;
9734 // 1. Build set of faces representing each side
9735 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9736 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9738 // =======================================================================
9739 // 1. Build set of faces representing each side:
9740 // =======================================================================
9741 // a. build set of nodes belonging to faces
9742 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9743 // c. create temporary faces representing side of volumes if correspondent
9744 // face does not exist
9746 SMESHDS_Mesh* aMesh = GetMeshDS();
9747 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9748 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9749 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9750 set<const SMDS_MeshElement*> volSet1, volSet2;
9751 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9752 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9753 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9754 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9755 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9756 int iSide, iFace, iNode;
9758 list<const SMDS_MeshElement* > tempFaceList;
9759 for ( iSide = 0; iSide < 2; iSide++ ) {
9760 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9761 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9762 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9763 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9764 set<const SMDS_MeshElement*>::iterator vIt;
9765 TIDSortedElemSet::iterator eIt;
9766 set<const SMDS_MeshNode*>::iterator nIt;
9768 // check that given nodes belong to given elements
9769 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9770 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9771 int firstIndex = -1, secondIndex = -1;
9772 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9773 const SMDS_MeshElement* elem = *eIt;
9774 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9775 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9776 if ( firstIndex > -1 && secondIndex > -1 ) break;
9778 if ( firstIndex < 0 || secondIndex < 0 ) {
9779 // we can simply return until temporary faces created
9780 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9783 // -----------------------------------------------------------
9784 // 1a. Collect nodes of existing faces
9785 // and build set of face nodes in order to detect missing
9786 // faces corresponding to sides of volumes
9787 // -----------------------------------------------------------
9789 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9791 // loop on the given element of a side
9792 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9793 //const SMDS_MeshElement* elem = *eIt;
9794 const SMDS_MeshElement* elem = *eIt;
9795 if ( elem->GetType() == SMDSAbs_Face ) {
9796 faceSet->insert( elem );
9797 set <const SMDS_MeshNode*> faceNodeSet;
9798 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9799 while ( nodeIt->more() ) {
9800 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9801 nodeSet->insert( n );
9802 faceNodeSet.insert( n );
9804 setOfFaceNodeSet.insert( faceNodeSet );
9806 else if ( elem->GetType() == SMDSAbs_Volume )
9807 volSet->insert( elem );
9809 // ------------------------------------------------------------------------------
9810 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9811 // ------------------------------------------------------------------------------
9813 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9814 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9815 while ( fIt->more() ) { // loop on faces sharing a node
9816 const SMDS_MeshElement* f = fIt->next();
9817 if ( faceSet->find( f ) == faceSet->end() ) {
9818 // check if all nodes are in nodeSet and
9819 // complete setOfFaceNodeSet if they are
9820 set <const SMDS_MeshNode*> faceNodeSet;
9821 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9822 bool allInSet = true;
9823 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9824 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9825 if ( nodeSet->find( n ) == nodeSet->end() )
9828 faceNodeSet.insert( n );
9831 faceSet->insert( f );
9832 setOfFaceNodeSet.insert( faceNodeSet );
9838 // -------------------------------------------------------------------------
9839 // 1c. Create temporary faces representing sides of volumes if correspondent
9840 // face does not exist
9841 // -------------------------------------------------------------------------
9843 if ( !volSet->empty() ) {
9844 //int nodeSetSize = nodeSet->size();
9846 // loop on given volumes
9847 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9848 SMDS_VolumeTool vol (*vIt);
9849 // loop on volume faces: find free faces
9850 // --------------------------------------
9851 list<const SMDS_MeshElement* > freeFaceList;
9852 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9853 if ( !vol.IsFreeFace( iFace ))
9855 // check if there is already a face with same nodes in a face set
9856 const SMDS_MeshElement* aFreeFace = 0;
9857 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9858 int nbNodes = vol.NbFaceNodes( iFace );
9859 set <const SMDS_MeshNode*> faceNodeSet;
9860 vol.GetFaceNodes( iFace, faceNodeSet );
9861 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9863 // no such a face is given but it still can exist, check it
9864 if ( nbNodes == 3 ) {
9865 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9867 else if ( nbNodes == 4 ) {
9868 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9871 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9872 aFreeFace = aMesh->FindFace(poly_nodes);
9876 // create a temporary face
9877 if ( nbNodes == 3 ) {
9878 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9879 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9881 else if ( nbNodes == 4 ) {
9882 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9883 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9886 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9887 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9888 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9892 freeFaceList.push_back( aFreeFace );
9893 tempFaceList.push_back( aFreeFace );
9896 } // loop on faces of a volume
9898 // choose one of several free faces
9899 // --------------------------------------
9900 if ( freeFaceList.size() > 1 ) {
9901 // choose a face having max nb of nodes shared by other elems of a side
9902 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9903 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9904 while ( fIt != freeFaceList.end() ) { // loop on free faces
9905 int nbSharedNodes = 0;
9906 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9907 while ( nodeIt->more() ) { // loop on free face nodes
9908 const SMDS_MeshNode* n =
9909 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9910 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9911 while ( invElemIt->more() ) {
9912 const SMDS_MeshElement* e = invElemIt->next();
9913 if ( faceSet->find( e ) != faceSet->end() )
9915 if ( elemSet->find( e ) != elemSet->end() )
9919 if ( nbSharedNodes >= maxNbNodes ) {
9920 maxNbNodes = nbSharedNodes;
9924 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9926 if ( freeFaceList.size() > 1 )
9928 // could not choose one face, use another way
9929 // choose a face most close to the bary center of the opposite side
9930 gp_XYZ aBC( 0., 0., 0. );
9931 set <const SMDS_MeshNode*> addedNodes;
9932 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9933 eIt = elemSet2->begin();
9934 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9935 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9936 while ( nodeIt->more() ) { // loop on free face nodes
9937 const SMDS_MeshNode* n =
9938 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9939 if ( addedNodes.insert( n ).second )
9940 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9943 aBC /= addedNodes.size();
9944 double minDist = DBL_MAX;
9945 fIt = freeFaceList.begin();
9946 while ( fIt != freeFaceList.end() ) { // loop on free faces
9948 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9949 while ( nodeIt->more() ) { // loop on free face nodes
9950 const SMDS_MeshNode* n =
9951 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9952 gp_XYZ p( n->X(),n->Y(),n->Z() );
9953 dist += ( aBC - p ).SquareModulus();
9955 if ( dist < minDist ) {
9957 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9960 fIt = freeFaceList.erase( fIt++ );
9963 } // choose one of several free faces of a volume
9965 if ( freeFaceList.size() == 1 ) {
9966 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9967 faceSet->insert( aFreeFace );
9968 // complete a node set with nodes of a found free face
9969 // for ( iNode = 0; iNode < ; iNode++ )
9970 // nodeSet->insert( fNodes[ iNode ] );
9973 } // loop on volumes of a side
9975 // // complete a set of faces if new nodes in a nodeSet appeared
9976 // // ----------------------------------------------------------
9977 // if ( nodeSetSize != nodeSet->size() ) {
9978 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9979 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9980 // while ( fIt->more() ) { // loop on faces sharing a node
9981 // const SMDS_MeshElement* f = fIt->next();
9982 // if ( faceSet->find( f ) == faceSet->end() ) {
9983 // // check if all nodes are in nodeSet and
9984 // // complete setOfFaceNodeSet if they are
9985 // set <const SMDS_MeshNode*> faceNodeSet;
9986 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9987 // bool allInSet = true;
9988 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9989 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9990 // if ( nodeSet->find( n ) == nodeSet->end() )
9991 // allInSet = false;
9993 // faceNodeSet.insert( n );
9995 // if ( allInSet ) {
9996 // faceSet->insert( f );
9997 // setOfFaceNodeSet.insert( faceNodeSet );
10003 } // Create temporary faces, if there are volumes given
10006 if ( faceSet1.size() != faceSet2.size() ) {
10007 // delete temporary faces: they are in reverseElements of actual nodes
10008 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10009 // while ( tmpFaceIt->more() )
10010 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10011 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10012 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10013 // aMesh->RemoveElement(*tmpFaceIt);
10014 MESSAGE("Diff nb of faces");
10015 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10018 // ============================================================
10019 // 2. Find nodes to merge:
10020 // bind a node to remove to a node to put instead
10021 // ============================================================
10023 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10024 if ( theFirstNode1 != theFirstNode2 )
10025 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10026 if ( theSecondNode1 != theSecondNode2 )
10027 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10029 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10030 set< long > linkIdSet; // links to process
10031 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10033 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10034 list< NLink > linkList[2];
10035 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10036 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10037 // loop on links in linkList; find faces by links and append links
10038 // of the found faces to linkList
10039 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10040 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10041 NLink link[] = { *linkIt[0], *linkIt[1] };
10042 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10043 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10046 // by links, find faces in the face sets,
10047 // and find indices of link nodes in the found faces;
10048 // in a face set, there is only one or no face sharing a link
10049 // ---------------------------------------------------------------
10051 const SMDS_MeshElement* face[] = { 0, 0 };
10052 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10053 vector<const SMDS_MeshNode*> fnodes1(9);
10054 vector<const SMDS_MeshNode*> fnodes2(9);
10055 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10056 vector<const SMDS_MeshNode*> notLinkNodes1(6);
10057 vector<const SMDS_MeshNode*> notLinkNodes2(6);
10058 int iLinkNode[2][2];
10059 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10060 const SMDS_MeshNode* n1 = link[iSide].first;
10061 const SMDS_MeshNode* n2 = link[iSide].second;
10062 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10063 set< const SMDS_MeshElement* > fMap;
10064 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10065 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10066 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10067 while ( fIt->more() ) { // loop on faces sharing a node
10068 const SMDS_MeshElement* f = fIt->next();
10069 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10070 ! fMap.insert( f ).second ) // f encounters twice
10072 if ( face[ iSide ] ) {
10073 MESSAGE( "2 faces per link " );
10074 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10078 faceSet->erase( f );
10079 // get face nodes and find ones of a link
10084 fnodes1.resize(f->NbNodes()+1);
10085 notLinkNodes1.resize(f->NbNodes()-2);
10088 fnodes2.resize(f->NbNodes()+1);
10089 notLinkNodes2.resize(f->NbNodes()-2);
10092 if(!f->IsQuadratic()) {
10093 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10094 while ( nIt->more() ) {
10095 const SMDS_MeshNode* n =
10096 static_cast<const SMDS_MeshNode*>( nIt->next() );
10098 iLinkNode[ iSide ][ 0 ] = iNode;
10100 else if ( n == n2 ) {
10101 iLinkNode[ iSide ][ 1 ] = iNode;
10103 //else if ( notLinkNodes[ iSide ][ 0 ] )
10104 // notLinkNodes[ iSide ][ 1 ] = n;
10106 // notLinkNodes[ iSide ][ 0 ] = n;
10110 notLinkNodes1[nbl] = n;
10111 //notLinkNodes1.push_back(n);
10113 notLinkNodes2[nbl] = n;
10114 //notLinkNodes2.push_back(n);
10116 //faceNodes[ iSide ][ iNode++ ] = n;
10118 fnodes1[iNode++] = n;
10121 fnodes2[iNode++] = n;
10125 else { // f->IsQuadratic()
10126 const SMDS_VtkFace* F =
10127 dynamic_cast<const SMDS_VtkFace*>(f);
10128 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10129 // use special nodes iterator
10130 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10131 while ( anIter->more() ) {
10132 const SMDS_MeshNode* n =
10133 static_cast<const SMDS_MeshNode*>( anIter->next() );
10135 iLinkNode[ iSide ][ 0 ] = iNode;
10137 else if ( n == n2 ) {
10138 iLinkNode[ iSide ][ 1 ] = iNode;
10143 notLinkNodes1[nbl] = n;
10146 notLinkNodes2[nbl] = n;
10150 fnodes1[iNode++] = n;
10153 fnodes2[iNode++] = n;
10157 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10159 fnodes1[iNode] = fnodes1[0];
10162 fnodes2[iNode] = fnodes1[0];
10169 // check similarity of elements of the sides
10170 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10171 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10172 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10173 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10176 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10178 break; // do not return because it s necessary to remove tmp faces
10181 // set nodes to merge
10182 // -------------------
10184 if ( face[0] && face[1] ) {
10185 int nbNodes = face[0]->NbNodes();
10186 if ( nbNodes != face[1]->NbNodes() ) {
10187 MESSAGE("Diff nb of face nodes");
10188 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10189 break; // do not return because it s necessary to remove tmp faces
10191 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10192 if ( nbNodes == 3 ) {
10193 //nReplaceMap.insert( TNodeNodeMap::value_type
10194 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10195 nReplaceMap.insert( TNodeNodeMap::value_type
10196 ( notLinkNodes1[0], notLinkNodes2[0] ));
10199 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10200 // analyse link orientation in faces
10201 int i1 = iLinkNode[ iSide ][ 0 ];
10202 int i2 = iLinkNode[ iSide ][ 1 ];
10203 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10204 // if notLinkNodes are the first and the last ones, then
10205 // their order does not correspond to the link orientation
10206 if (( i1 == 1 && i2 == 2 ) ||
10207 ( i1 == 2 && i2 == 1 ))
10208 reverse[ iSide ] = !reverse[ iSide ];
10210 if ( reverse[0] == reverse[1] ) {
10211 //nReplaceMap.insert( TNodeNodeMap::value_type
10212 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10213 //nReplaceMap.insert( TNodeNodeMap::value_type
10214 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10215 for(int nn=0; nn<nbNodes-2; nn++) {
10216 nReplaceMap.insert( TNodeNodeMap::value_type
10217 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10221 //nReplaceMap.insert( TNodeNodeMap::value_type
10222 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10223 //nReplaceMap.insert( TNodeNodeMap::value_type
10224 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10225 for(int nn=0; nn<nbNodes-2; nn++) {
10226 nReplaceMap.insert( TNodeNodeMap::value_type
10227 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10232 // add other links of the faces to linkList
10233 // -----------------------------------------
10235 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10236 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10237 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10238 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10239 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10240 if ( !iter_isnew.second ) { // already in a set: no need to process
10241 linkIdSet.erase( iter_isnew.first );
10243 else // new in set == encountered for the first time: add
10245 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10246 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10247 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10248 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10249 linkList[0].push_back ( NLink( n1, n2 ));
10250 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10254 } // loop on link lists
10256 if ( aResult == SEW_OK &&
10257 ( linkIt[0] != linkList[0].end() ||
10258 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10259 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10260 " " << (faceSetPtr[1]->empty()));
10261 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10264 // ====================================================================
10265 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10266 // ====================================================================
10268 // delete temporary faces: they are in reverseElements of actual nodes
10269 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10270 // while ( tmpFaceIt->more() )
10271 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10272 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10273 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10274 // aMesh->RemoveElement(*tmpFaceIt);
10276 if ( aResult != SEW_OK)
10279 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10280 // loop on nodes replacement map
10281 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10282 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10283 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10284 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10285 nodeIDsToRemove.push_back( nToRemove->GetID() );
10286 // loop on elements sharing nToRemove
10287 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10288 while ( invElemIt->more() ) {
10289 const SMDS_MeshElement* e = invElemIt->next();
10290 // get a new suite of nodes: make replacement
10291 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10292 vector< const SMDS_MeshNode*> nodes( nbNodes );
10293 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10294 while ( nIt->more() ) {
10295 const SMDS_MeshNode* n =
10296 static_cast<const SMDS_MeshNode*>( nIt->next() );
10297 nnIt = nReplaceMap.find( n );
10298 if ( nnIt != nReplaceMap.end() ) {
10300 n = (*nnIt).second;
10304 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10305 // elemIDsToRemove.push_back( e->GetID() );
10309 SMDSAbs_ElementType etyp = e->GetType();
10310 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10313 myLastCreatedElems.Append(newElem);
10314 AddToSameGroups(newElem, e, aMesh);
10315 int aShapeId = e->getshapeId();
10318 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10321 aMesh->RemoveElement(e);
10326 Remove( nodeIDsToRemove, true );
10331 //================================================================================
10333 * \brief Find corresponding nodes in two sets of faces
10334 * \param theSide1 - first face set
10335 * \param theSide2 - second first face
10336 * \param theFirstNode1 - a boundary node of set 1
10337 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10338 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10339 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10340 * \param nReplaceMap - output map of corresponding nodes
10341 * \return bool - is a success or not
10343 //================================================================================
10346 //#define DEBUG_MATCHING_NODES
10349 SMESH_MeshEditor::Sew_Error
10350 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10351 set<const SMDS_MeshElement*>& theSide2,
10352 const SMDS_MeshNode* theFirstNode1,
10353 const SMDS_MeshNode* theFirstNode2,
10354 const SMDS_MeshNode* theSecondNode1,
10355 const SMDS_MeshNode* theSecondNode2,
10356 TNodeNodeMap & nReplaceMap)
10358 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10360 nReplaceMap.clear();
10361 if ( theFirstNode1 != theFirstNode2 )
10362 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10363 if ( theSecondNode1 != theSecondNode2 )
10364 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10366 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10367 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10369 list< NLink > linkList[2];
10370 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10371 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10373 // loop on links in linkList; find faces by links and append links
10374 // of the found faces to linkList
10375 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10376 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10377 NLink link[] = { *linkIt[0], *linkIt[1] };
10378 if ( linkSet.find( link[0] ) == linkSet.end() )
10381 // by links, find faces in the face sets,
10382 // and find indices of link nodes in the found faces;
10383 // in a face set, there is only one or no face sharing a link
10384 // ---------------------------------------------------------------
10386 const SMDS_MeshElement* face[] = { 0, 0 };
10387 list<const SMDS_MeshNode*> notLinkNodes[2];
10388 //bool reverse[] = { false, false }; // order of notLinkNodes
10390 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10392 const SMDS_MeshNode* n1 = link[iSide].first;
10393 const SMDS_MeshNode* n2 = link[iSide].second;
10394 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10395 set< const SMDS_MeshElement* > facesOfNode1;
10396 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10398 // during a loop of the first node, we find all faces around n1,
10399 // during a loop of the second node, we find one face sharing both n1 and n2
10400 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10401 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10402 while ( fIt->more() ) { // loop on faces sharing a node
10403 const SMDS_MeshElement* f = fIt->next();
10404 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10405 ! facesOfNode1.insert( f ).second ) // f encounters twice
10407 if ( face[ iSide ] ) {
10408 MESSAGE( "2 faces per link " );
10409 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10412 faceSet->erase( f );
10414 // get not link nodes
10415 int nbN = f->NbNodes();
10416 if ( f->IsQuadratic() )
10418 nbNodes[ iSide ] = nbN;
10419 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10420 int i1 = f->GetNodeIndex( n1 );
10421 int i2 = f->GetNodeIndex( n2 );
10422 int iEnd = nbN, iBeg = -1, iDelta = 1;
10423 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10425 std::swap( iEnd, iBeg ); iDelta = -1;
10430 if ( i == iEnd ) i = iBeg + iDelta;
10431 if ( i == i1 ) break;
10432 nodes.push_back ( f->GetNode( i ) );
10438 // check similarity of elements of the sides
10439 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10440 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10441 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10442 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10445 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10449 // set nodes to merge
10450 // -------------------
10452 if ( face[0] && face[1] ) {
10453 if ( nbNodes[0] != nbNodes[1] ) {
10454 MESSAGE("Diff nb of face nodes");
10455 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10457 #ifdef DEBUG_MATCHING_NODES
10458 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10459 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10460 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10462 int nbN = nbNodes[0];
10464 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10465 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10466 for ( int i = 0 ; i < nbN - 2; ++i ) {
10467 #ifdef DEBUG_MATCHING_NODES
10468 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10470 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10474 // add other links of the face 1 to linkList
10475 // -----------------------------------------
10477 const SMDS_MeshElement* f0 = face[0];
10478 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10479 for ( int i = 0; i < nbN; i++ )
10481 const SMDS_MeshNode* n2 = f0->GetNode( i );
10482 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10483 linkSet.insert( SMESH_TLink( n1, n2 ));
10484 if ( !iter_isnew.second ) { // already in a set: no need to process
10485 linkSet.erase( iter_isnew.first );
10487 else // new in set == encountered for the first time: add
10489 #ifdef DEBUG_MATCHING_NODES
10490 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10491 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10493 linkList[0].push_back ( NLink( n1, n2 ));
10494 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10499 } // loop on link lists
10504 //================================================================================
10506 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10507 \param theElems - the list of elements (edges or faces) to be replicated
10508 The nodes for duplication could be found from these elements
10509 \param theNodesNot - list of nodes to NOT replicate
10510 \param theAffectedElems - the list of elements (cells and edges) to which the
10511 replicated nodes should be associated to.
10512 \return TRUE if operation has been completed successfully, FALSE otherwise
10514 //================================================================================
10516 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10517 const TIDSortedElemSet& theNodesNot,
10518 const TIDSortedElemSet& theAffectedElems )
10520 myLastCreatedElems.Clear();
10521 myLastCreatedNodes.Clear();
10523 if ( theElems.size() == 0 )
10526 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10531 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10532 // duplicate elements and nodes
10533 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10534 // replce nodes by duplications
10535 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10539 //================================================================================
10541 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10542 \param theMeshDS - mesh instance
10543 \param theElems - the elements replicated or modified (nodes should be changed)
10544 \param theNodesNot - nodes to NOT replicate
10545 \param theNodeNodeMap - relation of old node to new created node
10546 \param theIsDoubleElem - flag os to replicate element or modify
10547 \return TRUE if operation has been completed successfully, FALSE otherwise
10549 //================================================================================
10551 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10552 const TIDSortedElemSet& theElems,
10553 const TIDSortedElemSet& theNodesNot,
10554 std::map< const SMDS_MeshNode*,
10555 const SMDS_MeshNode* >& theNodeNodeMap,
10556 const bool theIsDoubleElem )
10558 MESSAGE("doubleNodes");
10559 // iterate on through element and duplicate them (by nodes duplication)
10561 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10562 for ( ; elemItr != theElems.end(); ++elemItr )
10564 const SMDS_MeshElement* anElem = *elemItr;
10568 bool isDuplicate = false;
10569 // duplicate nodes to duplicate element
10570 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10571 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10573 while ( anIter->more() )
10576 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10577 SMDS_MeshNode* aNewNode = aCurrNode;
10578 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10579 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10580 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10583 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10584 theNodeNodeMap[ aCurrNode ] = aNewNode;
10585 myLastCreatedNodes.Append( aNewNode );
10587 isDuplicate |= (aCurrNode != aNewNode);
10588 newNodes[ ind++ ] = aNewNode;
10590 if ( !isDuplicate )
10593 if ( theIsDoubleElem )
10594 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10597 MESSAGE("ChangeElementNodes");
10598 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10605 //================================================================================
10607 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10608 \param theNodes - identifiers of nodes to be doubled
10609 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10610 nodes. If list of element identifiers is empty then nodes are doubled but
10611 they not assigned to elements
10612 \return TRUE if operation has been completed successfully, FALSE otherwise
10614 //================================================================================
10616 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10617 const std::list< int >& theListOfModifiedElems )
10619 MESSAGE("DoubleNodes");
10620 myLastCreatedElems.Clear();
10621 myLastCreatedNodes.Clear();
10623 if ( theListOfNodes.size() == 0 )
10626 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10630 // iterate through nodes and duplicate them
10632 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10634 std::list< int >::const_iterator aNodeIter;
10635 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10637 int aCurr = *aNodeIter;
10638 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10644 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10647 anOldNodeToNewNode[ aNode ] = aNewNode;
10648 myLastCreatedNodes.Append( aNewNode );
10652 // Create map of new nodes for modified elements
10654 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10656 std::list< int >::const_iterator anElemIter;
10657 for ( anElemIter = theListOfModifiedElems.begin();
10658 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10660 int aCurr = *anElemIter;
10661 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10665 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10667 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10669 while ( anIter->more() )
10671 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10672 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10674 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10675 aNodeArr[ ind++ ] = aNewNode;
10678 aNodeArr[ ind++ ] = aCurrNode;
10680 anElemToNodes[ anElem ] = aNodeArr;
10683 // Change nodes of elements
10685 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10686 anElemToNodesIter = anElemToNodes.begin();
10687 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10689 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10690 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10693 MESSAGE("ChangeElementNodes");
10694 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10703 //================================================================================
10705 \brief Check if element located inside shape
10706 \return TRUE if IN or ON shape, FALSE otherwise
10708 //================================================================================
10710 template<class Classifier>
10711 bool isInside(const SMDS_MeshElement* theElem,
10712 Classifier& theClassifier,
10713 const double theTol)
10715 gp_XYZ centerXYZ (0, 0, 0);
10716 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10717 while (aNodeItr->more())
10718 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10720 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10721 theClassifier.Perform(aPnt, theTol);
10722 TopAbs_State aState = theClassifier.State();
10723 return (aState == TopAbs_IN || aState == TopAbs_ON );
10726 //================================================================================
10728 * \brief Classifier of the 3D point on the TopoDS_Face
10729 * with interaface suitable for isInside()
10731 //================================================================================
10733 struct _FaceClassifier
10735 Extrema_ExtPS _extremum;
10736 BRepAdaptor_Surface _surface;
10737 TopAbs_State _state;
10739 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10741 _extremum.Initialize( _surface,
10742 _surface.FirstUParameter(), _surface.LastUParameter(),
10743 _surface.FirstVParameter(), _surface.LastVParameter(),
10744 _surface.Tolerance(), _surface.Tolerance() );
10746 void Perform(const gp_Pnt& aPnt, double theTol)
10748 _state = TopAbs_OUT;
10749 _extremum.Perform(aPnt);
10750 if ( _extremum.IsDone() )
10751 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10752 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10754 TopAbs_State State() const
10761 //================================================================================
10763 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10764 \param theElems - group of of elements (edges or faces) to be replicated
10765 \param theNodesNot - group of nodes not to replicate
10766 \param theShape - shape to detect affected elements (element which geometric center
10767 located on or inside shape).
10768 The replicated nodes should be associated to affected elements.
10769 \return TRUE if operation has been completed successfully, FALSE otherwise
10771 //================================================================================
10773 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10774 const TIDSortedElemSet& theNodesNot,
10775 const TopoDS_Shape& theShape )
10777 if ( theShape.IsNull() )
10780 const double aTol = Precision::Confusion();
10781 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10782 auto_ptr<_FaceClassifier> aFaceClassifier;
10783 if ( theShape.ShapeType() == TopAbs_SOLID )
10785 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10786 bsc3d->PerformInfinitePoint(aTol);
10788 else if (theShape.ShapeType() == TopAbs_FACE )
10790 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10793 // iterates on indicated elements and get elements by back references from their nodes
10794 TIDSortedElemSet anAffected;
10795 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10796 for ( ; elemItr != theElems.end(); ++elemItr )
10798 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10802 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10803 while ( nodeItr->more() )
10805 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10806 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10808 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10809 while ( backElemItr->more() )
10811 const SMDS_MeshElement* curElem = backElemItr->next();
10812 if ( curElem && theElems.find(curElem) == theElems.end() &&
10814 isInside( curElem, *bsc3d, aTol ) :
10815 isInside( curElem, *aFaceClassifier, aTol )))
10816 anAffected.insert( curElem );
10820 return DoubleNodes( theElems, theNodesNot, anAffected );
10824 * \brief compute an oriented angle between two planes defined by four points.
10825 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10826 * @param p0 base of the rotation axe
10827 * @param p1 extremity of the rotation axe
10828 * @param g1 belongs to the first plane
10829 * @param g2 belongs to the second plane
10831 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10833 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10834 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10835 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10836 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10837 gp_Vec vref(p0, p1);
10840 gp_Vec n1 = vref.Crossed(v1);
10841 gp_Vec n2 = vref.Crossed(v2);
10842 return n2.AngleWithRef(n1, vref);
10846 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10847 * The list of groups must describe a partition of the mesh volumes.
10848 * The nodes of the internal faces at the boundaries of the groups are doubled.
10849 * In option, the internal faces are replaced by flat elements.
10850 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10851 * The flat elements are stored in groups of volumes.
10852 * @param theElems - list of groups of volumes, where a group of volume is a set of
10853 * SMDS_MeshElements sorted by Id.
10854 * @param createJointElems - if TRUE, create the elements
10855 * @return TRUE if operation has been completed successfully, FALSE otherwise
10857 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10858 bool createJointElems)
10860 MESSAGE("----------------------------------------------");
10861 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10862 MESSAGE("----------------------------------------------");
10864 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10865 meshDS->BuildDownWardConnectivity(true);
10867 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10869 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10870 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10871 // build the list of nodes shared by 2 or more domains, with their domain indexes
10873 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10874 std::map<int,int>celldom; // cell vtkId --> domain
10875 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10876 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10877 faceDomains.clear();
10879 cellDomains.clear();
10880 nodeDomains.clear();
10881 std::map<int,int> emptyMap;
10882 std::set<int> emptySet;
10885 for (int idom = 0; idom < theElems.size(); idom++)
10888 // --- build a map (face to duplicate --> volume to modify)
10889 // with all the faces shared by 2 domains (group of elements)
10890 // and corresponding volume of this domain, for each shared face.
10891 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10893 const TIDSortedElemSet& domain = theElems[idom];
10894 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10895 for (; elemItr != domain.end(); ++elemItr)
10897 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10900 int vtkId = anElem->getVtkId();
10901 int neighborsVtkIds[NBMAXNEIGHBORS];
10902 int downIds[NBMAXNEIGHBORS];
10903 unsigned char downTypes[NBMAXNEIGHBORS];
10904 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10905 for (int n = 0; n < nbNeighbors; n++)
10907 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10908 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10909 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10911 DownIdType face(downIds[n], downTypes[n]);
10912 if (!faceDomains.count(face))
10913 faceDomains[face] = emptyMap; // create an empty entry for face
10914 if (!faceDomains[face].count(idom))
10916 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10917 celldom[vtkId] = idom;
10924 //MESSAGE("Number of shared faces " << faceDomains.size());
10925 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10927 // --- explore the shared faces domain by domain,
10928 // explore the nodes of the face and see if they belong to a cell in the domain,
10929 // which has only a node or an edge on the border (not a shared face)
10931 for (int idomain = 0; idomain < theElems.size(); idomain++)
10933 const TIDSortedElemSet& domain = theElems[idomain];
10934 itface = faceDomains.begin();
10935 for (; itface != faceDomains.end(); ++itface)
10937 std::map<int, int> domvol = itface->second;
10938 if (!domvol.count(idomain))
10940 DownIdType face = itface->first;
10941 //MESSAGE(" --- face " << face.cellId);
10942 std::set<int> oldNodes;
10944 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10945 std::set<int>::iterator itn = oldNodes.begin();
10946 for (; itn != oldNodes.end(); ++itn)
10949 //MESSAGE(" node " << oldId);
10950 std::set<int> cells;
10952 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10953 for (int i=0; i<l.ncells; i++)
10955 int vtkId = l.cells[i];
10956 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10957 if (!domain.count(anElem))
10959 int vtkType = grid->GetCellType(vtkId);
10960 int downId = grid->CellIdToDownId(vtkId);
10961 DownIdType aCell(downId, vtkType);
10962 if (celldom.count(vtkId))
10964 cellDomains[aCell][idomain] = vtkId;
10965 celldom[vtkId] = idomain;
10971 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10972 // for each shared face, get the nodes
10973 // for each node, for each domain of the face, create a clone of the node
10975 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10976 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10977 // the value is the ordered domain ids. (more than 4 domains not taken into account)
10979 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10980 std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10982 for (int idomain = 0; idomain < theElems.size(); idomain++)
10984 itface = faceDomains.begin();
10985 for (; itface != faceDomains.end(); ++itface)
10987 std::map<int, int> domvol = itface->second;
10988 if (!domvol.count(idomain))
10990 DownIdType face = itface->first;
10991 //MESSAGE(" --- face " << face.cellId);
10992 std::set<int> oldNodes;
10994 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10995 bool isMultipleDetected = false;
10996 std::set<int>::iterator itn = oldNodes.begin();
10997 for (; itn != oldNodes.end(); ++itn)
11000 //MESSAGE(" node " << oldId);
11001 if (!nodeDomains.count(oldId))
11002 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11003 if (nodeDomains[oldId].empty())
11004 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11005 std::map<int, int>::iterator itdom = domvol.begin();
11006 for (; itdom != domvol.end(); ++itdom)
11008 int idom = itdom->first;
11009 //MESSAGE(" domain " << idom);
11010 if (!nodeDomains[oldId].count(idom)) // --- node to clone
11012 if (nodeDomains[oldId].size() >= 2) // a multiple node
11014 vector<int> orderedDoms;
11015 //MESSAGE("multiple node " << oldId);
11016 isMultipleDetected =true;
11017 if (mutipleNodes.count(oldId))
11018 orderedDoms = mutipleNodes[oldId];
11021 map<int,int>::iterator it = nodeDomains[oldId].begin();
11022 for (; it != nodeDomains[oldId].end(); ++it)
11023 orderedDoms.push_back(it->first);
11025 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11026 //stringstream txt;
11027 //for (int i=0; i<orderedDoms.size(); i++)
11028 // txt << orderedDoms[i] << " ";
11029 //MESSAGE("orderedDoms " << txt.str());
11030 mutipleNodes[oldId] = orderedDoms;
11032 double *coords = grid->GetPoint(oldId);
11033 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11034 int newId = newNode->getVtkId();
11035 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11036 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11040 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11042 //MESSAGE("multiple Nodes detected on a shared face");
11043 int downId = itface->first.cellId;
11044 unsigned char cellType = itface->first.cellType;
11045 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11046 const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11047 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11048 for (int ie =0; ie < nbEdges; ie++)
11051 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11052 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11054 vector<int> vn0 = mutipleNodes[nodes[0]];
11055 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11056 sort( vn0.begin(), vn0.end() );
11057 sort( vn1.begin(), vn1.end() );
11060 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11061 double *coords = grid->GetPoint(nodes[0]);
11062 gp_Pnt p0(coords[0], coords[1], coords[2]);
11063 coords = grid->GetPoint(nodes[nbNodes - 1]);
11064 gp_Pnt p1(coords[0], coords[1], coords[2]);
11066 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11067 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11068 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11069 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11070 for (int id=0; id < vn0.size(); id++)
11072 int idom = vn0[id];
11073 for (int ivol=0; ivol<nbvol; ivol++)
11075 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11076 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11077 if (theElems[idom].count(elem))
11079 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11080 domvol[idom] = svol;
11081 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11083 vtkIdType npts = 0;
11084 vtkIdType* pts = 0;
11085 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11086 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11089 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11090 angleDom[idom] = 0;
11094 gp_Pnt g(values[0], values[1], values[2]);
11095 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11096 //MESSAGE(" angle=" << angleDom[idom]);
11102 map<double, int> sortedDom; // sort domains by angle
11103 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11104 sortedDom[ia->second] = ia->first;
11105 vector<int> vnodes;
11107 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11109 vdom.push_back(ib->second);
11110 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11112 for (int ino = 0; ino < nbNodes; ino++)
11113 vnodes.push_back(nodes[ino]);
11114 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11122 // --- iterate on shared faces (volumes to modify, face to extrude)
11123 // get node id's of the face (id SMDS = id VTK)
11124 // create flat element with old and new nodes if requested
11126 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11127 // (domain1 X domain2) = domain1 + MAXINT*domain2
11129 std::map<int, std::map<long,int> > nodeQuadDomains;
11130 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11132 if (createJointElems)
11134 itface = faceDomains.begin();
11135 for (; itface != faceDomains.end(); ++itface)
11137 DownIdType face = itface->first;
11138 std::set<int> oldNodes;
11139 std::set<int>::iterator itn;
11141 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11143 std::map<int, int> domvol = itface->second;
11144 std::map<int, int>::iterator itdom = domvol.begin();
11145 int dom1 = itdom->first;
11146 int vtkVolId = itdom->second;
11148 int dom2 = itdom->first;
11149 SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11151 stringstream grpname;
11152 grpname << "junction_";
11154 grpname << dom1 << "_" << dom2;
11156 grpname << dom2 << "_" << dom1;
11158 string namegrp = grpname.str();
11159 if (!mapOfJunctionGroups.count(namegrp))
11160 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11161 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11163 sgrp->Add(vol->GetID());
11167 // --- create volumes on multiple domain intersection if requested
11168 // iterate on edgesMultiDomains
11170 if (createJointElems)
11172 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11173 for (; ite != edgesMultiDomains.end(); ++ite)
11175 vector<int> nodes = ite->first;
11176 vector<int> orderDom = ite->second;
11177 vector<vtkIdType> orderedNodes;
11178 if (nodes.size() == 2)
11180 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11181 for (int ino=0; ino < nodes.size(); ino++)
11182 if (orderDom.size() == 3)
11183 for (int idom = 0; idom <orderDom.size(); idom++)
11184 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11186 for (int idom = orderDom.size()-1; idom >=0; idom--)
11187 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11188 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11190 stringstream grpname;
11191 grpname << "junction_";
11192 grpname << 0 << "_" << 0;
11194 string namegrp = grpname.str();
11195 if (!mapOfJunctionGroups.count(namegrp))
11196 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11197 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11199 sgrp->Add(vol->GetID());
11203 // TODO quadratic nodes
11208 // --- list the explicit faces and edges of the mesh that need to be modified,
11209 // i.e. faces and edges built with one or more duplicated nodes.
11210 // associate these faces or edges to their corresponding domain.
11211 // only the first domain found is kept when a face or edge is shared
11213 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11214 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11215 faceOrEdgeDom.clear();
11218 for (int idomain = 0; idomain < theElems.size(); idomain++)
11220 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11221 for (; itnod != nodeDomains.end(); ++itnod)
11223 int oldId = itnod->first;
11224 //MESSAGE(" node " << oldId);
11225 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11226 for (int i = 0; i < l.ncells; i++)
11228 int vtkId = l.cells[i];
11229 int vtkType = grid->GetCellType(vtkId);
11230 int downId = grid->CellIdToDownId(vtkId);
11231 DownIdType aCell(downId, vtkType);
11232 int volParents[1000];
11233 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11234 for (int j = 0; j < nbvol; j++)
11235 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11236 if (!feDom.count(vtkId))
11238 feDom[vtkId] = idomain;
11239 faceOrEdgeDom[aCell] = emptyMap;
11240 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11241 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11242 // << " type " << vtkType << " downId " << downId);
11248 // --- iterate on shared faces (volumes to modify, face to extrude)
11249 // get node id's of the face
11250 // replace old nodes by new nodes in volumes, and update inverse connectivity
11252 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11253 for (int m=0; m<3; m++)
11255 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11256 itface = (*amap).begin();
11257 for (; itface != (*amap).end(); ++itface)
11259 DownIdType face = itface->first;
11260 std::set<int> oldNodes;
11261 std::set<int>::iterator itn;
11263 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11264 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11265 std::map<int, int> localClonedNodeIds;
11267 std::map<int, int> domvol = itface->second;
11268 std::map<int, int>::iterator itdom = domvol.begin();
11269 for (; itdom != domvol.end(); ++itdom)
11271 int idom = itdom->first;
11272 int vtkVolId = itdom->second;
11273 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11274 localClonedNodeIds.clear();
11275 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11278 if (nodeDomains[oldId].count(idom))
11280 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11281 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11284 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11289 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11290 grid->BuildLinks();
11298 * \brief Double nodes on some external faces and create flat elements.
11299 * Flat elements are mainly used by some types of mechanic calculations.
11301 * Each group of the list must be constituted of faces.
11302 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11303 * @param theElems - list of groups of faces, where a group of faces is a set of
11304 * SMDS_MeshElements sorted by Id.
11305 * @return TRUE if operation has been completed successfully, FALSE otherwise
11307 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11309 MESSAGE("-------------------------------------------------");
11310 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11311 MESSAGE("-------------------------------------------------");
11313 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11315 // --- For each group of faces
11316 // duplicate the nodes, create a flat element based on the face
11317 // replace the nodes of the faces by their clones
11319 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11320 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11321 clonedNodes.clear();
11322 intermediateNodes.clear();
11324 for (int idom = 0; idom < theElems.size(); idom++)
11326 const TIDSortedElemSet& domain = theElems[idom];
11327 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11328 for (; elemItr != domain.end(); ++elemItr)
11330 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11331 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11334 // MESSAGE("aFace=" << aFace->GetID());
11335 bool isQuad = aFace->IsQuadratic();
11336 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11338 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11340 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11341 while (nodeIt->more())
11343 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11344 bool isMedium = isQuad && (aFace->IsMediumNode(node));
11346 ln2.push_back(node);
11348 ln0.push_back(node);
11350 const SMDS_MeshNode* clone = 0;
11351 if (!clonedNodes.count(node))
11353 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11354 clonedNodes[node] = clone;
11357 clone = clonedNodes[node];
11360 ln3.push_back(clone);
11362 ln1.push_back(clone);
11364 const SMDS_MeshNode* inter = 0;
11365 if (isQuad && (!isMedium))
11367 if (!intermediateNodes.count(node))
11369 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11370 intermediateNodes[node] = inter;
11373 inter = intermediateNodes[node];
11374 ln4.push_back(inter);
11378 // --- extrude the face
11380 vector<const SMDS_MeshNode*> ln;
11381 SMDS_MeshVolume* vol = 0;
11382 vtkIdType aType = aFace->GetVtkType();
11386 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11387 // MESSAGE("vol prism " << vol->GetID());
11388 ln.push_back(ln1[0]);
11389 ln.push_back(ln1[1]);
11390 ln.push_back(ln1[2]);
11393 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11394 // MESSAGE("vol hexa " << vol->GetID());
11395 ln.push_back(ln1[0]);
11396 ln.push_back(ln1[1]);
11397 ln.push_back(ln1[2]);
11398 ln.push_back(ln1[3]);
11400 case VTK_QUADRATIC_TRIANGLE:
11401 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11402 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11403 // MESSAGE("vol quad prism " << vol->GetID());
11404 ln.push_back(ln1[0]);
11405 ln.push_back(ln1[1]);
11406 ln.push_back(ln1[2]);
11407 ln.push_back(ln3[0]);
11408 ln.push_back(ln3[1]);
11409 ln.push_back(ln3[2]);
11411 case VTK_QUADRATIC_QUAD:
11412 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11413 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11414 // ln4[0], ln4[1], ln4[2], ln4[3]);
11415 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11416 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11417 ln4[0], ln4[1], ln4[2], ln4[3]);
11418 // MESSAGE("vol quad hexa " << vol->GetID());
11419 ln.push_back(ln1[0]);
11420 ln.push_back(ln1[1]);
11421 ln.push_back(ln1[2]);
11422 ln.push_back(ln1[3]);
11423 ln.push_back(ln3[0]);
11424 ln.push_back(ln3[1]);
11425 ln.push_back(ln3[2]);
11426 ln.push_back(ln3[3]);
11434 // --- modify the face
11436 aFace->ChangeNodes(&ln[0], ln.size());
11442 //================================================================================
11444 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11445 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11446 * \return TRUE if operation has been completed successfully, FALSE otherwise
11448 //================================================================================
11450 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11452 // iterates on volume elements and detect all free faces on them
11453 SMESHDS_Mesh* aMesh = GetMeshDS();
11456 //bool res = false;
11457 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11458 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11461 const SMDS_MeshVolume* volume = vIt->next();
11462 SMDS_VolumeTool vTool( volume );
11463 vTool.SetExternalNormal();
11464 const bool isPoly = volume->IsPoly();
11465 const bool isQuad = volume->IsQuadratic();
11466 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11468 if (!vTool.IsFreeFace(iface))
11471 vector<const SMDS_MeshNode *> nodes;
11472 int nbFaceNodes = vTool.NbFaceNodes(iface);
11473 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11475 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11476 nodes.push_back(faceNodes[inode]);
11478 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11479 nodes.push_back(faceNodes[inode]);
11481 // add new face based on volume nodes
11482 if (aMesh->FindFace( nodes ) ) {
11484 continue; // face already exsist
11486 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11490 return ( nbFree==(nbExisted+nbCreated) );
11495 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11497 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11499 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11502 //================================================================================
11504 * \brief Creates missing boundary elements
11505 * \param elements - elements whose boundary is to be checked
11506 * \param dimension - defines type of boundary elements to create
11507 * \param group - a group to store created boundary elements in
11508 * \param targetMesh - a mesh to store created boundary elements in
11509 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11510 * \param toCopyExistingBondary - if true, not only new but also pre-existing
11511 * boundary elements will be copied into the targetMesh
11512 * \param toAddExistingBondary - if true, not only new but also pre-existing
11513 * boundary elements will be added into the new group
11514 * \param aroundElements - if true, elements will be created on boundary of given
11515 * elements else, on boundary of the whole mesh. This
11516 * option works for 2D elements only.
11517 * \return nb of added boundary elements
11519 //================================================================================
11521 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11522 Bnd_Dimension dimension,
11523 SMESH_Group* group/*=0*/,
11524 SMESH_Mesh* targetMesh/*=0*/,
11525 bool toCopyElements/*=false*/,
11526 bool toCopyExistingBondary/*=false*/,
11527 bool toAddExistingBondary/*= false*/,
11528 bool aroundElements/*= false*/)
11530 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11531 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11532 // hope that all elements are of the same type, do not check them all
11533 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11534 throw SALOME_Exception(LOCALIZED("wrong element type"));
11536 if ( aroundElements && elemType == SMDSAbs_Volume )
11537 throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11540 toCopyElements = toCopyExistingBondary = false;
11542 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11543 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11544 int nbAddedBnd = 0;
11546 // editor adding present bnd elements and optionally holding elements to add to the group
11547 SMESH_MeshEditor* presentEditor;
11548 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11549 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11551 SMDS_VolumeTool vTool;
11552 TIDSortedElemSet avoidSet;
11553 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11556 typedef vector<const SMDS_MeshNode*> TConnectivity;
11558 SMDS_ElemIteratorPtr eIt;
11559 if (elements.empty())
11560 eIt = aMesh->elementsIterator(elemType);
11562 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11564 while (eIt->more())
11566 const SMDS_MeshElement* elem = eIt->next();
11567 const int iQuad = elem->IsQuadratic();
11569 // ------------------------------------------------------------------------------------
11570 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11571 // ------------------------------------------------------------------------------------
11572 vector<const SMDS_MeshElement*> presentBndElems;
11573 vector<TConnectivity> missingBndElems;
11574 TConnectivity nodes;
11575 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11577 vTool.SetExternalNormal();
11578 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11580 if (!vTool.IsFreeFace(iface))
11582 int nbFaceNodes = vTool.NbFaceNodes(iface);
11583 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11584 if ( missType == SMDSAbs_Edge ) // boundary edges
11586 nodes.resize( 2+iQuad );
11587 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11589 for ( int j = 0; j < nodes.size(); ++j )
11591 if ( const SMDS_MeshElement* edge =
11592 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11593 presentBndElems.push_back( edge );
11595 missingBndElems.push_back( nodes );
11598 else // boundary face
11601 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11602 nodes.push_back( nn[inode] );
11604 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11605 nodes.push_back( nn[inode] );
11607 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11608 presentBndElems.push_back( f );
11610 missingBndElems.push_back( nodes );
11614 else // elem is a face ------------------------------------------
11616 avoidSet.clear(), avoidSet.insert( elem );
11617 int nbNodes = elem->NbCornerNodes();
11618 nodes.resize( 2 /*+ iQuad*/);
11619 for ( int i = 0; i < nbNodes; i++ )
11621 nodes[0] = elem->GetNode(i);
11622 nodes[1] = elem->GetNode((i+1)%nbNodes);
11623 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11624 continue; // not free link
11627 //nodes[2] = elem->GetNode( i + nbNodes );
11628 if ( const SMDS_MeshElement* edge =
11629 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11630 presentBndElems.push_back( edge );
11632 missingBndElems.push_back( nodes );
11636 // ---------------------------------
11637 // 2. Add missing boundary elements
11638 // ---------------------------------
11639 if ( targetMesh != myMesh )
11640 // instead of making a map of nodes in this mesh and targetMesh,
11641 // we create nodes with same IDs. We can renumber them later, if needed
11642 for ( int i = 0; i < missingBndElems.size(); ++i )
11644 TConnectivity& srcNodes = missingBndElems[i];
11645 TConnectivity nodes( srcNodes.size() );
11646 for ( inode = 0; inode < nodes.size(); ++inode )
11647 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11648 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11650 /*noMedium=*/true))
11652 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11656 for ( int i = 0; i < missingBndElems.size(); ++i )
11658 TConnectivity& nodes = missingBndElems[i];
11659 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11661 /*noMedium=*/true))
11663 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11667 // ----------------------------------
11668 // 3. Copy present boundary elements
11669 // ----------------------------------
11670 if ( toCopyExistingBondary )
11671 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11673 const SMDS_MeshElement* e = presentBndElems[i];
11674 TConnectivity nodes( e->NbNodes() );
11675 for ( inode = 0; inode < nodes.size(); ++inode )
11676 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11677 presentEditor->AddElement(nodes, missType, e->IsPoly());
11679 else // store present elements to add them to a group
11680 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11682 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11685 } // loop on given elements
11687 // ---------------------------------------------
11688 // 4. Fill group with boundary elements
11689 // ---------------------------------------------
11692 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11693 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11694 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11696 tgtEditor.myLastCreatedElems.Clear();
11697 tgtEditor2.myLastCreatedElems.Clear();
11699 // -----------------------
11700 // 5. Copy given elements
11701 // -----------------------
11702 if ( toCopyElements && targetMesh != myMesh )
11704 if (elements.empty())
11705 eIt = aMesh->elementsIterator(elemType);
11707 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11708 while (eIt->more())
11710 const SMDS_MeshElement* elem = eIt->next();
11711 TConnectivity nodes( elem->NbNodes() );
11712 for ( inode = 0; inode < nodes.size(); ++inode )
11713 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11714 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11716 tgtEditor.myLastCreatedElems.Clear();