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>
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101 using namespace SMESH::Controls;
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
108 //=======================================================================
109 //function : SMESH_MeshEditor
111 //=======================================================================
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114 :myMesh( theMesh ) // theMesh may be NULL
118 //=======================================================================
122 //=======================================================================
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126 const SMDSAbs_ElementType type,
130 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131 SMDS_MeshElement* e = 0;
132 int nbnode = node.size();
133 SMESHDS_Mesh* mesh = GetMeshDS();
138 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
139 else e = mesh->AddFace (node[0], node[1], node[2] );
141 else if (nbnode == 4) {
142 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
143 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
145 else if (nbnode == 6) {
146 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
147 node[4], node[5], ID);
148 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
151 else if (nbnode == 8) {
152 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
153 node[4], node[5], node[6], node[7], ID);
154 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
155 node[4], node[5], node[6], node[7] );
158 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
159 else e = mesh->AddPolygonalFace (node );
166 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
169 else if (nbnode == 5) {
170 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
172 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
175 else if (nbnode == 6) {
176 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
177 node[4], node[5], ID);
178 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
181 else if (nbnode == 8) {
182 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183 node[4], node[5], node[6], node[7], ID);
184 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
185 node[4], node[5], node[6], node[7] );
187 else if (nbnode == 10) {
188 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7],
190 node[8], node[9], ID);
191 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
192 node[4], node[5], node[6], node[7],
195 else if (nbnode == 13) {
196 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197 node[4], node[5], node[6], node[7],
198 node[8], node[9], node[10],node[11],
200 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
201 node[4], node[5], node[6], node[7],
202 node[8], node[9], node[10],node[11],
205 else if (nbnode == 15) {
206 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207 node[4], node[5], node[6], node[7],
208 node[8], node[9], node[10],node[11],
209 node[12],node[13],node[14],ID);
210 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
211 node[4], node[5], node[6], node[7],
212 node[8], node[9], node[10],node[11],
213 node[12],node[13],node[14] );
215 else if (nbnode == 20) {
216 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
217 node[4], node[5], node[6], node[7],
218 node[8], node[9], node[10],node[11],
219 node[12],node[13],node[14],node[15],
220 node[16],node[17],node[18],node[19],ID);
221 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
222 node[4], node[5], node[6], node[7],
223 node[8], node[9], node[10],node[11],
224 node[12],node[13],node[14],node[15],
225 node[16],node[17],node[18],node[19] );
232 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
233 else e = mesh->AddEdge (node[0], node[1] );
235 else if ( nbnode == 3 ) {
236 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
237 else e = mesh->AddEdge (node[0], node[1], node[2] );
241 case SMDSAbs_0DElement:
243 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
244 else e = mesh->Add0DElement (node[0] );
249 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
250 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
255 if ( e ) myLastCreatedElems.Append( e );
259 //=======================================================================
263 //=======================================================================
265 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
266 const SMDSAbs_ElementType type,
270 vector<const SMDS_MeshNode*> nodes;
271 nodes.reserve( nodeIDs.size() );
272 vector<int>::const_iterator id = nodeIDs.begin();
273 while ( id != nodeIDs.end() ) {
274 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
275 nodes.push_back( node );
279 return AddElement( nodes, type, isPoly, ID );
282 //=======================================================================
284 //purpose : Remove a node or an element.
285 // Modify a compute state of sub-meshes which become empty
286 //=======================================================================
288 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
291 myLastCreatedElems.Clear();
292 myLastCreatedNodes.Clear();
294 SMESHDS_Mesh* aMesh = GetMeshDS();
295 set< SMESH_subMesh *> smmap;
298 list<int>::const_iterator it = theIDs.begin();
299 for ( ; it != theIDs.end(); it++ ) {
300 const SMDS_MeshElement * elem;
302 elem = aMesh->FindNode( *it );
304 elem = aMesh->FindElement( *it );
308 // Notify VERTEX sub-meshes about modification
310 const SMDS_MeshNode* node = cast2Node( elem );
311 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
312 if ( int aShapeID = node->getshapeId() )
313 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
316 // Find sub-meshes to notify about modification
317 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
318 // while ( nodeIt->more() ) {
319 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
320 // const SMDS_PositionPtr& aPosition = node->GetPosition();
321 // if ( aPosition.get() ) {
322 // if ( int aShapeID = aPosition->GetShapeId() ) {
323 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
324 // smmap.insert( sm );
331 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
333 aMesh->RemoveElement( elem );
337 // Notify sub-meshes about modification
338 if ( !smmap.empty() ) {
339 set< SMESH_subMesh *>::iterator smIt;
340 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
341 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
344 // // Check if the whole mesh becomes empty
345 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
346 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
351 //=======================================================================
352 //function : FindShape
353 //purpose : Return an index of the shape theElem is on
354 // or zero if a shape not found
355 //=======================================================================
357 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
359 myLastCreatedElems.Clear();
360 myLastCreatedNodes.Clear();
362 SMESHDS_Mesh * aMesh = GetMeshDS();
363 if ( aMesh->ShapeToMesh().IsNull() )
366 if ( theElem->GetType() == SMDSAbs_Node )
368 int aShapeID = theElem->getshapeId();
375 TopoDS_Shape aShape; // the shape a node is on
376 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
377 while ( nodeIt->more() ) {
378 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
379 int aShapeID = node->getshapeId();
381 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
383 if ( sm->Contains( theElem ))
385 if ( aShape.IsNull() )
386 aShape = aMesh->IndexToShape( aShapeID );
389 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
394 // None of nodes is on a proper shape,
395 // find the shape among ancestors of aShape on which a node is
396 if ( aShape.IsNull() ) {
397 //MESSAGE ("::FindShape() - NONE node is on shape")
400 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
401 for ( ; ancIt.More(); ancIt.Next() ) {
402 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
403 if ( sm && sm->Contains( theElem ))
404 return aMesh->ShapeToIndex( ancIt.Value() );
407 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
411 //=======================================================================
412 //function : IsMedium
414 //=======================================================================
416 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
417 const SMDSAbs_ElementType typeToCheck)
419 bool isMedium = false;
420 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
421 while (it->more() && !isMedium ) {
422 const SMDS_MeshElement* elem = it->next();
423 isMedium = elem->IsMediumNode(node);
428 //=======================================================================
429 //function : ShiftNodesQuadTria
431 // Shift nodes in the array corresponded to quadratic triangle
432 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
433 //=======================================================================
434 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
436 const SMDS_MeshNode* nd1 = aNodes[0];
437 aNodes[0] = aNodes[1];
438 aNodes[1] = aNodes[2];
440 const SMDS_MeshNode* nd2 = aNodes[3];
441 aNodes[3] = aNodes[4];
442 aNodes[4] = aNodes[5];
446 //=======================================================================
447 //function : GetNodesFromTwoTria
449 // Shift nodes in the array corresponded to quadratic triangle
450 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
451 //=======================================================================
452 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
453 const SMDS_MeshElement * theTria2,
454 const SMDS_MeshNode* N1[],
455 const SMDS_MeshNode* N2[])
457 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
460 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
463 if(it->more()) return false;
464 it = theTria2->nodesIterator();
467 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
470 if(it->more()) return false;
472 int sames[3] = {-1,-1,-1};
484 if(nbsames!=2) return false;
486 ShiftNodesQuadTria(N1);
488 ShiftNodesQuadTria(N1);
491 i = sames[0] + sames[1] + sames[2];
493 ShiftNodesQuadTria(N2);
495 // now we receive following N1 and N2 (using numeration as above image)
496 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
497 // i.e. first nodes from both arrays determ new diagonal
501 //=======================================================================
502 //function : InverseDiag
503 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
504 // but having other common link.
505 // Return False if args are improper
506 //=======================================================================
508 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
509 const SMDS_MeshElement * theTria2 )
511 MESSAGE("InverseDiag");
512 myLastCreatedElems.Clear();
513 myLastCreatedNodes.Clear();
515 if (!theTria1 || !theTria2)
518 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
519 if (!F1) return false;
520 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
521 if (!F2) return false;
522 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
523 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
525 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
526 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
530 // put nodes in array and find out indices of the same ones
531 const SMDS_MeshNode* aNodes [6];
532 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
534 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
535 while ( it->more() ) {
536 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
538 if ( i > 2 ) // theTria2
539 // find same node of theTria1
540 for ( int j = 0; j < 3; j++ )
541 if ( aNodes[ i ] == aNodes[ j ]) {
550 return false; // theTria1 is not a triangle
551 it = theTria2->nodesIterator();
553 if ( i == 6 && it->more() )
554 return false; // theTria2 is not a triangle
557 // find indices of 1,2 and of A,B in theTria1
558 int iA = 0, iB = 0, i1 = 0, i2 = 0;
559 for ( i = 0; i < 6; i++ ) {
560 if ( sameInd [ i ] == 0 ) {
569 // nodes 1 and 2 should not be the same
570 if ( aNodes[ i1 ] == aNodes[ i2 ] )
574 aNodes[ iA ] = aNodes[ i2 ];
576 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
578 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
579 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
583 } // end if(F1 && F2)
585 // check case of quadratic faces
586 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
588 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
592 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
593 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
601 const SMDS_MeshNode* N1 [6];
602 const SMDS_MeshNode* N2 [6];
603 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
605 // now we receive following N1 and N2 (using numeration as above image)
606 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
607 // i.e. first nodes from both arrays determ new diagonal
609 const SMDS_MeshNode* N1new [6];
610 const SMDS_MeshNode* N2new [6];
623 // replaces nodes in faces
624 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
625 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
630 //=======================================================================
631 //function : findTriangles
632 //purpose : find triangles sharing theNode1-theNode2 link
633 //=======================================================================
635 static bool findTriangles(const SMDS_MeshNode * theNode1,
636 const SMDS_MeshNode * theNode2,
637 const SMDS_MeshElement*& theTria1,
638 const SMDS_MeshElement*& theTria2)
640 if ( !theNode1 || !theNode2 ) return false;
642 theTria1 = theTria2 = 0;
644 set< const SMDS_MeshElement* > emap;
645 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
647 const SMDS_MeshElement* elem = it->next();
648 if ( elem->NbNodes() == 3 )
651 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
653 const SMDS_MeshElement* elem = it->next();
654 if ( emap.find( elem ) != emap.end() ) {
656 // theTria1 must be element with minimum ID
657 if( theTria1->GetID() < elem->GetID() ) {
671 return ( theTria1 && theTria2 );
674 //=======================================================================
675 //function : InverseDiag
676 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
677 // with ones built on the same 4 nodes but having other common link.
678 // Return false if proper faces not found
679 //=======================================================================
681 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
682 const SMDS_MeshNode * theNode2)
684 myLastCreatedElems.Clear();
685 myLastCreatedNodes.Clear();
687 MESSAGE( "::InverseDiag()" );
689 const SMDS_MeshElement *tr1, *tr2;
690 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
693 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
694 if (!F1) return false;
695 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
696 if (!F2) return false;
697 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
698 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
700 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
701 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
705 // put nodes in array
706 // and find indices of 1,2 and of A in tr1 and of B in tr2
707 int i, iA1 = 0, i1 = 0;
708 const SMDS_MeshNode* aNodes1 [3];
709 SMDS_ElemIteratorPtr it;
710 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
711 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
712 if ( aNodes1[ i ] == theNode1 )
713 iA1 = i; // node A in tr1
714 else if ( aNodes1[ i ] != theNode2 )
718 const SMDS_MeshNode* aNodes2 [3];
719 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
720 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
721 if ( aNodes2[ i ] == theNode2 )
722 iB2 = i; // node B in tr2
723 else if ( aNodes2[ i ] != theNode1 )
727 // nodes 1 and 2 should not be the same
728 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
732 aNodes1[ iA1 ] = aNodes2[ i2 ];
734 aNodes2[ iB2 ] = aNodes1[ i1 ];
736 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
737 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
742 // check case of quadratic faces
743 return InverseDiag(tr1,tr2);
746 //=======================================================================
747 //function : getQuadrangleNodes
748 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
749 // fusion of triangles tr1 and tr2 having shared link on
750 // theNode1 and theNode2
751 //=======================================================================
753 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
754 const SMDS_MeshNode * theNode1,
755 const SMDS_MeshNode * theNode2,
756 const SMDS_MeshElement * tr1,
757 const SMDS_MeshElement * tr2 )
759 if( tr1->NbNodes() != tr2->NbNodes() )
761 // find the 4-th node to insert into tr1
762 const SMDS_MeshNode* n4 = 0;
763 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
765 while ( !n4 && i<3 ) {
766 const SMDS_MeshNode * n = cast2Node( it->next() );
768 bool isDiag = ( n == theNode1 || n == theNode2 );
772 // Make an array of nodes to be in a quadrangle
773 int iNode = 0, iFirstDiag = -1;
774 it = tr1->nodesIterator();
777 const SMDS_MeshNode * n = cast2Node( it->next() );
779 bool isDiag = ( n == theNode1 || n == theNode2 );
781 if ( iFirstDiag < 0 )
783 else if ( iNode - iFirstDiag == 1 )
784 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
786 else if ( n == n4 ) {
787 return false; // tr1 and tr2 should not have all the same nodes
789 theQuadNodes[ iNode++ ] = n;
791 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
792 theQuadNodes[ iNode ] = n4;
797 //=======================================================================
798 //function : DeleteDiag
799 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
800 // with a quadrangle built on the same 4 nodes.
801 // Return false if proper faces not found
802 //=======================================================================
804 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
805 const SMDS_MeshNode * theNode2)
807 myLastCreatedElems.Clear();
808 myLastCreatedNodes.Clear();
810 MESSAGE( "::DeleteDiag()" );
812 const SMDS_MeshElement *tr1, *tr2;
813 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
816 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
817 if (!F1) return false;
818 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
819 if (!F2) return false;
820 SMESHDS_Mesh * aMesh = GetMeshDS();
822 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
823 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
825 const SMDS_MeshNode* aNodes [ 4 ];
826 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
829 const SMDS_MeshElement* newElem = 0;
830 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
831 myLastCreatedElems.Append(newElem);
832 AddToSameGroups( newElem, tr1, aMesh );
833 int aShapeId = tr1->getshapeId();
836 aMesh->SetMeshElementOnShape( newElem, aShapeId );
838 aMesh->RemoveElement( tr1 );
839 aMesh->RemoveElement( tr2 );
844 // check case of quadratic faces
845 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
847 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
851 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
852 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
860 const SMDS_MeshNode* N1 [6];
861 const SMDS_MeshNode* N2 [6];
862 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
864 // now we receive following N1 and N2 (using numeration as above image)
865 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
866 // i.e. first nodes from both arrays determ new diagonal
868 const SMDS_MeshNode* aNodes[8];
878 const SMDS_MeshElement* newElem = 0;
879 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
880 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
881 myLastCreatedElems.Append(newElem);
882 AddToSameGroups( newElem, tr1, aMesh );
883 int aShapeId = tr1->getshapeId();
886 aMesh->SetMeshElementOnShape( newElem, aShapeId );
888 aMesh->RemoveElement( tr1 );
889 aMesh->RemoveElement( tr2 );
891 // remove middle node (9)
892 GetMeshDS()->RemoveNode( N1[4] );
897 //=======================================================================
898 //function : Reorient
899 //purpose : Reverse theElement orientation
900 //=======================================================================
902 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
905 myLastCreatedElems.Clear();
906 myLastCreatedNodes.Clear();
910 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
911 if ( !it || !it->more() )
914 switch ( theElem->GetType() ) {
918 if(!theElem->IsQuadratic()) {
919 int i = theElem->NbNodes();
920 vector<const SMDS_MeshNode*> aNodes( i );
922 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
923 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
926 // quadratic elements
927 if(theElem->GetType()==SMDSAbs_Edge) {
928 vector<const SMDS_MeshNode*> aNodes(3);
929 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
930 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
931 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
932 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
935 int nbn = theElem->NbNodes();
936 vector<const SMDS_MeshNode*> aNodes(nbn);
937 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
939 for(; i<nbn/2; i++) {
940 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
942 for(i=0; i<nbn/2; i++) {
943 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
945 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
949 case SMDSAbs_Volume: {
950 if (theElem->IsPoly()) {
951 // TODO reorient vtk polyhedron
952 MESSAGE("reorient vtk polyhedron ?");
953 const SMDS_VtkVolume* aPolyedre =
954 dynamic_cast<const SMDS_VtkVolume*>( theElem );
956 MESSAGE("Warning: bad volumic element");
960 int nbFaces = aPolyedre->NbFaces();
961 vector<const SMDS_MeshNode *> poly_nodes;
962 vector<int> quantities (nbFaces);
964 // reverse each face of the polyedre
965 for (int iface = 1; iface <= nbFaces; iface++) {
966 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
967 quantities[iface - 1] = nbFaceNodes;
969 for (inode = nbFaceNodes; inode >= 1; inode--) {
970 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
971 poly_nodes.push_back(curNode);
975 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
979 SMDS_VolumeTool vTool;
980 if ( !vTool.Set( theElem ))
983 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
984 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
993 //=======================================================================
994 //function : getBadRate
996 //=======================================================================
998 static double getBadRate (const SMDS_MeshElement* theElem,
999 SMESH::Controls::NumericalFunctorPtr& theCrit)
1001 SMESH::Controls::TSequenceOfXYZ P;
1002 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1004 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1005 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1008 //=======================================================================
1009 //function : QuadToTri
1010 //purpose : Cut quadrangles into triangles.
1011 // theCrit is used to select a diagonal to cut
1012 //=======================================================================
1014 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1015 SMESH::Controls::NumericalFunctorPtr theCrit)
1017 myLastCreatedElems.Clear();
1018 myLastCreatedNodes.Clear();
1020 MESSAGE( "::QuadToTri()" );
1022 if ( !theCrit.get() )
1025 SMESHDS_Mesh * aMesh = GetMeshDS();
1027 Handle(Geom_Surface) surface;
1028 SMESH_MesherHelper helper( *GetMesh() );
1030 TIDSortedElemSet::iterator itElem;
1031 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1032 const SMDS_MeshElement* elem = *itElem;
1033 if ( !elem || elem->GetType() != SMDSAbs_Face )
1035 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1038 // retrieve element nodes
1039 const SMDS_MeshNode* aNodes [8];
1040 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1042 while ( itN->more() )
1043 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1045 // compare two sets of possible triangles
1046 double aBadRate1, aBadRate2; // to what extent a set is bad
1047 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1048 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1049 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1051 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1052 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1053 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1055 int aShapeId = FindShape( elem );
1056 const SMDS_MeshElement* newElem1 = 0;
1057 const SMDS_MeshElement* newElem2 = 0;
1059 if( !elem->IsQuadratic() ) {
1061 // split liner quadrangle
1062 if ( aBadRate1 <= aBadRate2 ) {
1063 // tr1 + tr2 is better
1064 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1065 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1068 // tr3 + tr4 is better
1069 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1070 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1075 // split quadratic quadrangle
1077 // get surface elem is on
1078 if ( aShapeId != helper.GetSubShapeID() ) {
1082 shape = aMesh->IndexToShape( aShapeId );
1083 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1084 TopoDS_Face face = TopoDS::Face( shape );
1085 surface = BRep_Tool::Surface( face );
1086 if ( !surface.IsNull() )
1087 helper.SetSubShape( shape );
1091 const SMDS_MeshNode* aNodes [8];
1092 const SMDS_MeshNode* inFaceNode = 0;
1093 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1095 while ( itN->more() ) {
1096 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1097 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1098 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1100 inFaceNode = aNodes[ i-1 ];
1103 // find middle point for (0,1,2,3)
1104 // and create a node in this point;
1106 if ( surface.IsNull() ) {
1108 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1112 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1115 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1117 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1119 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1120 myLastCreatedNodes.Append(newN);
1122 // create a new element
1123 const SMDS_MeshNode* N[6];
1124 if ( aBadRate1 <= aBadRate2 ) {
1131 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1132 aNodes[6], aNodes[7], newN );
1133 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1134 newN, aNodes[4], aNodes[5] );
1143 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1144 aNodes[7], aNodes[4], newN );
1145 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1146 newN, aNodes[5], aNodes[6] );
1150 // care of a new element
1152 myLastCreatedElems.Append(newElem1);
1153 myLastCreatedElems.Append(newElem2);
1154 AddToSameGroups( newElem1, elem, aMesh );
1155 AddToSameGroups( newElem2, elem, aMesh );
1157 // put a new triangle on the same shape
1160 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1161 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1163 aMesh->RemoveElement( elem );
1168 //=======================================================================
1169 //function : BestSplit
1170 //purpose : Find better diagonal for cutting.
1171 //=======================================================================
1173 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1174 SMESH::Controls::NumericalFunctorPtr theCrit)
1176 myLastCreatedElems.Clear();
1177 myLastCreatedNodes.Clear();
1182 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1185 if( theQuad->NbNodes()==4 ||
1186 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1188 // retrieve element nodes
1189 const SMDS_MeshNode* aNodes [4];
1190 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1192 //while (itN->more())
1194 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1196 // compare two sets of possible triangles
1197 double aBadRate1, aBadRate2; // to what extent a set is bad
1198 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1199 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1200 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1202 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1203 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1204 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1206 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1207 return 1; // diagonal 1-3
1209 return 2; // diagonal 2-4
1216 // Methods of splitting volumes into tetra
1218 const int theHexTo5_1[5*4+1] =
1220 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1222 const int theHexTo5_2[5*4+1] =
1224 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1226 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1228 const int theHexTo6_1[6*4+1] =
1230 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
1232 const int theHexTo6_2[6*4+1] =
1234 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
1236 const int theHexTo6_3[6*4+1] =
1238 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
1240 const int theHexTo6_4[6*4+1] =
1242 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
1244 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1246 const int thePyraTo2_1[2*4+1] =
1248 0, 1, 2, 4, 0, 2, 3, 4, -1
1250 const int thePyraTo2_2[2*4+1] =
1252 1, 2, 3, 4, 1, 3, 0, 4, -1
1254 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1256 const int thePentaTo3_1[3*4+1] =
1258 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1260 const int thePentaTo3_2[3*4+1] =
1262 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1264 const int thePentaTo3_3[3*4+1] =
1266 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1268 const int thePentaTo3_4[3*4+1] =
1270 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1272 const int thePentaTo3_5[3*4+1] =
1274 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1276 const int thePentaTo3_6[3*4+1] =
1278 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1280 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1281 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1283 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1286 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1287 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1288 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1293 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1294 bool _baryNode; //!< additional node is to be created at cell barycenter
1295 bool _ownConn; //!< to delete _connectivity in destructor
1296 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1298 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1299 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1300 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1301 bool hasFacet( const TTriangleFacet& facet ) const
1303 const int* tetConn = _connectivity;
1304 for ( ; tetConn[0] >= 0; tetConn += 4 )
1305 if (( facet.contains( tetConn[0] ) +
1306 facet.contains( tetConn[1] ) +
1307 facet.contains( tetConn[2] ) +
1308 facet.contains( tetConn[3] )) == 3 )
1314 //=======================================================================
1316 * \brief return TSplitMethod for the given element
1318 //=======================================================================
1320 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1322 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1324 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1325 // an edge and a face barycenter; tertaherdons are based on triangles and
1326 // a volume barycenter
1327 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1329 // Find out how adjacent volumes are split
1331 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1332 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1333 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1335 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1336 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1337 if ( nbNodes < 4 ) continue;
1339 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1340 const int* nInd = vol.GetFaceNodesIndices( iF );
1343 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1344 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1345 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1346 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1350 int iCom = 0; // common node of triangle faces to split into
1351 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1353 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1354 nInd[ iQ * ( (iCom+1)%nbNodes )],
1355 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1356 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1357 nInd[ iQ * ( (iCom+2)%nbNodes )],
1358 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1359 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1361 triaSplits.push_back( t012 );
1362 triaSplits.push_back( t023 );
1367 if ( !triaSplits.empty() )
1368 hasAdjacentSplits = true;
1371 // Among variants of split method select one compliant with adjacent volumes
1373 TSplitMethod method;
1374 if ( !vol.Element()->IsPoly() && !is24TetMode )
1376 int nbVariants = 2, nbTet = 0;
1377 const int** connVariants = 0;
1378 switch ( vol.Element()->GetEntityType() )
1380 case SMDSEntity_Hexa:
1381 case SMDSEntity_Quad_Hexa:
1382 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1383 connVariants = theHexTo5, nbTet = 5;
1385 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1387 case SMDSEntity_Pyramid:
1388 case SMDSEntity_Quad_Pyramid:
1389 connVariants = thePyraTo2; nbTet = 2;
1391 case SMDSEntity_Penta:
1392 case SMDSEntity_Quad_Penta:
1393 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1398 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1400 // check method compliancy with adjacent tetras,
1401 // all found splits must be among facets of tetras described by this method
1402 method = TSplitMethod( nbTet, connVariants[variant] );
1403 if ( hasAdjacentSplits && method._nbTetra > 0 )
1405 bool facetCreated = true;
1406 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1408 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1409 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1410 facetCreated = method.hasFacet( *facet );
1412 if ( !facetCreated )
1413 method = TSplitMethod(0); // incompatible method
1417 if ( method._nbTetra < 1 )
1419 // No standard method is applicable, use a generic solution:
1420 // each facet of a volume is split into triangles and
1421 // each of triangles and a volume barycenter form a tetrahedron.
1423 int* connectivity = new int[ maxTetConnSize + 1 ];
1424 method._connectivity = connectivity;
1425 method._ownConn = true;
1426 method._baryNode = true;
1429 int baryCenInd = vol.NbNodes();
1430 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1432 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1433 const int* nInd = vol.GetFaceNodesIndices( iF );
1434 // find common node of triangle facets of tetra to create
1435 int iCommon = 0; // index in linear numeration
1436 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1437 if ( !triaSplits.empty() )
1440 const TTriangleFacet* facet = &triaSplits.front();
1441 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1442 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1443 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1446 else if ( nbNodes > 3 && !is24TetMode )
1448 // find the best method of splitting into triangles by aspect ratio
1449 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1450 map< double, int > badness2iCommon;
1451 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1452 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1453 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1454 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1456 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1457 nodes[ iQ*((iLast-1)%nbNodes)],
1458 nodes[ iQ*((iLast )%nbNodes)]);
1459 double badness = getBadRate( &tria, aspectRatio );
1460 badness2iCommon.insert( make_pair( badness, iCommon ));
1462 // use iCommon with lowest badness
1463 iCommon = badness2iCommon.begin()->second;
1465 if ( iCommon >= nbNodes )
1466 iCommon = 0; // something wrong
1468 // fill connectivity of tetrahedra based on a current face
1469 int nbTet = nbNodes - 2;
1470 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1472 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1473 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1475 for ( int i = 0; i < nbTet; ++i )
1477 int i1 = i, i2 = (i+1) % nbNodes;
1478 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1479 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1480 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1481 connectivity[ connSize++ ] = faceBaryCenInd;
1482 connectivity[ connSize++ ] = baryCenInd;
1487 for ( int i = 0; i < nbTet; ++i )
1489 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1490 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1492 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1493 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1494 connectivity[ connSize++ ] = baryCenInd;
1497 method._nbTetra += nbTet;
1499 connectivity[ connSize++ ] = -1;
1503 //================================================================================
1505 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1507 //================================================================================
1509 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1511 // find the tetrahedron including the three nodes of facet
1512 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1513 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1514 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1515 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1516 while ( volIt1->more() )
1518 const SMDS_MeshElement* v = volIt1->next();
1519 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1521 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1522 while ( volIt2->more() )
1523 if ( v != volIt2->next() )
1525 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1526 while ( volIt3->more() )
1527 if ( v == volIt3->next() )
1533 //=======================================================================
1535 * \brief A key of a face of volume
1537 //=======================================================================
1539 struct TVolumeFaceKey: pair< int, pair< int, int> >
1541 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1543 TIDSortedNodeSet sortedNodes;
1544 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1545 int nbNodes = vol.NbFaceNodes( iF );
1546 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1547 for ( int i = 0; i < nbNodes; i += iQ )
1548 sortedNodes.insert( fNodes[i] );
1549 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1550 first = (*(n++))->GetID();
1551 second.first = (*(n++))->GetID();
1552 second.second = (*(n++))->GetID();
1557 //=======================================================================
1558 //function : SplitVolumesIntoTetra
1559 //purpose : Split volumic elements into tetrahedra.
1560 //=======================================================================
1562 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1563 const int theMethodFlags)
1565 // std-like iterator on coordinates of nodes of mesh element
1566 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1567 NXyzIterator xyzEnd;
1569 SMDS_VolumeTool volTool;
1570 SMESH_MesherHelper helper( *GetMesh());
1572 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1573 SMESHDS_SubMesh* fSubMesh = subMesh;
1575 SMESH_SequenceOfElemPtr newNodes, newElems;
1577 // map face of volume to it's baricenrtic node
1578 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1581 TIDSortedElemSet::const_iterator elem = theElems.begin();
1582 for ( ; elem != theElems.end(); ++elem )
1584 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1585 if ( geomType <= SMDSEntity_Quad_Tetra )
1586 continue; // tetra or face or ...
1588 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1590 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1591 if ( splitMethod._nbTetra < 1 ) continue;
1593 // find submesh to add new tetras to
1594 if ( !subMesh || !subMesh->Contains( *elem ))
1596 int shapeID = FindShape( *elem );
1597 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1598 subMesh = GetMeshDS()->MeshElements( shapeID );
1601 if ( (*elem)->IsQuadratic() )
1604 // add quadratic links to the helper
1605 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1607 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1608 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1609 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1611 helper.SetIsQuadratic( true );
1616 helper.SetIsQuadratic( false );
1618 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1619 if ( splitMethod._baryNode )
1621 // make a node at barycenter
1622 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1623 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1624 nodes.push_back( gcNode );
1625 newNodes.Append( gcNode );
1627 if ( !splitMethod._faceBaryNode.empty() )
1629 // make or find baricentric nodes of faces
1630 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1631 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1633 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1634 volFace2BaryNode.insert
1635 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1638 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1639 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1641 nodes.push_back( iF_n->second = f_n->second );
1646 helper.SetElementsOnShape( true );
1647 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1648 const int* tetConn = splitMethod._connectivity;
1649 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1650 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1651 nodes[ tetConn[1] ],
1652 nodes[ tetConn[2] ],
1653 nodes[ tetConn[3] ]));
1655 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1657 // Split faces on sides of the split volume
1659 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1660 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1662 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1663 if ( nbNodes < 4 ) continue;
1665 // find an existing face
1666 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1667 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1668 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1671 helper.SetElementsOnShape( false );
1672 vector< const SMDS_MeshElement* > triangles;
1674 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1675 if ( iF_n != splitMethod._faceBaryNode.end() )
1677 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1679 const SMDS_MeshNode* n1 = fNodes[iN];
1680 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1681 const SMDS_MeshNode *n3 = iF_n->second;
1682 if ( !volTool.IsFaceExternal( iF ))
1684 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1689 // among possible triangles create ones discribed by split method
1690 const int* nInd = volTool.GetFaceNodesIndices( iF );
1691 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1692 int iCom = 0; // common node of triangle faces to split into
1693 list< TTriangleFacet > facets;
1694 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1696 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1697 nInd[ iQ * ( (iCom+1)%nbNodes )],
1698 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1699 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1700 nInd[ iQ * ( (iCom+2)%nbNodes )],
1701 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1702 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1704 facets.push_back( t012 );
1705 facets.push_back( t023 );
1706 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1707 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1708 nInd[ iQ * ((iLast-1)%nbNodes )],
1709 nInd[ iQ * ((iLast )%nbNodes )]));
1713 list< TTriangleFacet >::iterator facet = facets.begin();
1714 for ( ; facet != facets.end(); ++facet )
1716 if ( !volTool.IsFaceExternal( iF ))
1717 swap( facet->_n2, facet->_n3 );
1718 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1719 volNodes[ facet->_n2 ],
1720 volNodes[ facet->_n3 ]));
1723 // find submesh to add new triangles in
1724 if ( !fSubMesh || !fSubMesh->Contains( face ))
1726 int shapeID = FindShape( face );
1727 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1729 for ( int i = 0; i < triangles.size(); ++i )
1731 if ( !triangles[i] ) continue;
1733 fSubMesh->AddElement( triangles[i]);
1734 newElems.Append( triangles[i] );
1736 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1737 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1740 } // loop on volume faces to split them into triangles
1742 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1744 } // loop on volumes to split
1746 myLastCreatedNodes = newNodes;
1747 myLastCreatedElems = newElems;
1750 //=======================================================================
1751 //function : AddToSameGroups
1752 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1753 //=======================================================================
1755 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1756 const SMDS_MeshElement* elemInGroups,
1757 SMESHDS_Mesh * aMesh)
1759 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1760 if (!groups.empty()) {
1761 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1762 for ( ; grIt != groups.end(); grIt++ ) {
1763 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1764 if ( group && group->Contains( elemInGroups ))
1765 group->SMDSGroup().Add( elemToAdd );
1771 //=======================================================================
1772 //function : RemoveElemFromGroups
1773 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1774 //=======================================================================
1775 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1776 SMESHDS_Mesh * aMesh)
1778 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1779 if (!groups.empty())
1781 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1782 for (; GrIt != groups.end(); GrIt++)
1784 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1785 if (!grp || grp->IsEmpty()) continue;
1786 grp->SMDSGroup().Remove(removeelem);
1791 //================================================================================
1793 * \brief Replace elemToRm by elemToAdd in the all groups
1795 //================================================================================
1797 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1798 const SMDS_MeshElement* elemToAdd,
1799 SMESHDS_Mesh * aMesh)
1801 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1802 if (!groups.empty()) {
1803 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1804 for ( ; grIt != groups.end(); grIt++ ) {
1805 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1806 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1807 group->SMDSGroup().Add( elemToAdd );
1812 //================================================================================
1814 * \brief Replace elemToRm by elemToAdd in the all groups
1816 //================================================================================
1818 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1819 const vector<const SMDS_MeshElement*>& elemToAdd,
1820 SMESHDS_Mesh * aMesh)
1822 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1823 if (!groups.empty())
1825 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1826 for ( ; grIt != groups.end(); grIt++ ) {
1827 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1828 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1829 for ( int i = 0; i < elemToAdd.size(); ++i )
1830 group->SMDSGroup().Add( elemToAdd[ i ] );
1835 //=======================================================================
1836 //function : QuadToTri
1837 //purpose : Cut quadrangles into triangles.
1838 // theCrit is used to select a diagonal to cut
1839 //=======================================================================
1841 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1842 const bool the13Diag)
1844 myLastCreatedElems.Clear();
1845 myLastCreatedNodes.Clear();
1847 MESSAGE( "::QuadToTri()" );
1849 SMESHDS_Mesh * aMesh = GetMeshDS();
1851 Handle(Geom_Surface) surface;
1852 SMESH_MesherHelper helper( *GetMesh() );
1854 TIDSortedElemSet::iterator itElem;
1855 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1856 const SMDS_MeshElement* elem = *itElem;
1857 if ( !elem || elem->GetType() != SMDSAbs_Face )
1859 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1860 if(!isquad) continue;
1862 if(elem->NbNodes()==4) {
1863 // retrieve element nodes
1864 const SMDS_MeshNode* aNodes [4];
1865 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1867 while ( itN->more() )
1868 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1870 int aShapeId = FindShape( elem );
1871 const SMDS_MeshElement* newElem1 = 0;
1872 const SMDS_MeshElement* newElem2 = 0;
1874 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1875 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1878 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1879 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1881 myLastCreatedElems.Append(newElem1);
1882 myLastCreatedElems.Append(newElem2);
1883 // put a new triangle on the same shape and add to the same groups
1886 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1887 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1889 AddToSameGroups( newElem1, elem, aMesh );
1890 AddToSameGroups( newElem2, elem, aMesh );
1891 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1892 aMesh->RemoveElement( elem );
1895 // Quadratic quadrangle
1897 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1899 // get surface elem is on
1900 int aShapeId = FindShape( elem );
1901 if ( aShapeId != helper.GetSubShapeID() ) {
1905 shape = aMesh->IndexToShape( aShapeId );
1906 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1907 TopoDS_Face face = TopoDS::Face( shape );
1908 surface = BRep_Tool::Surface( face );
1909 if ( !surface.IsNull() )
1910 helper.SetSubShape( shape );
1914 const SMDS_MeshNode* aNodes [8];
1915 const SMDS_MeshNode* inFaceNode = 0;
1916 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1918 while ( itN->more() ) {
1919 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1920 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1921 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1923 inFaceNode = aNodes[ i-1 ];
1927 // find middle point for (0,1,2,3)
1928 // and create a node in this point;
1930 if ( surface.IsNull() ) {
1932 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1936 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1939 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1941 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1943 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1944 myLastCreatedNodes.Append(newN);
1946 // create a new element
1947 const SMDS_MeshElement* newElem1 = 0;
1948 const SMDS_MeshElement* newElem2 = 0;
1949 const SMDS_MeshNode* N[6];
1957 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1958 aNodes[6], aNodes[7], newN );
1959 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1960 newN, aNodes[4], aNodes[5] );
1969 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1970 aNodes[7], aNodes[4], newN );
1971 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1972 newN, aNodes[5], aNodes[6] );
1974 myLastCreatedElems.Append(newElem1);
1975 myLastCreatedElems.Append(newElem2);
1976 // put a new triangle on the same shape and add to the same groups
1979 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1980 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1982 AddToSameGroups( newElem1, elem, aMesh );
1983 AddToSameGroups( newElem2, elem, aMesh );
1984 aMesh->RemoveElement( elem );
1991 //=======================================================================
1992 //function : getAngle
1994 //=======================================================================
1996 double getAngle(const SMDS_MeshElement * tr1,
1997 const SMDS_MeshElement * tr2,
1998 const SMDS_MeshNode * n1,
1999 const SMDS_MeshNode * n2)
2001 double angle = 2*PI; // bad angle
2004 SMESH::Controls::TSequenceOfXYZ P1, P2;
2005 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2006 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2009 if(!tr1->IsQuadratic())
2010 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2012 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2013 if ( N1.SquareMagnitude() <= gp::Resolution() )
2015 if(!tr2->IsQuadratic())
2016 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2018 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2019 if ( N2.SquareMagnitude() <= gp::Resolution() )
2022 // find the first diagonal node n1 in the triangles:
2023 // take in account a diagonal link orientation
2024 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2025 for ( int t = 0; t < 2; t++ ) {
2026 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2027 int i = 0, iDiag = -1;
2028 while ( it->more()) {
2029 const SMDS_MeshElement *n = it->next();
2030 if ( n == n1 || n == n2 ) {
2034 if ( i - iDiag == 1 )
2035 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2044 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2047 angle = N1.Angle( N2 );
2052 // =================================================
2053 // class generating a unique ID for a pair of nodes
2054 // and able to return nodes by that ID
2055 // =================================================
2059 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2060 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2063 long GetLinkID (const SMDS_MeshNode * n1,
2064 const SMDS_MeshNode * n2) const
2066 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2069 bool GetNodes (const long theLinkID,
2070 const SMDS_MeshNode* & theNode1,
2071 const SMDS_MeshNode* & theNode2) const
2073 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2074 if ( !theNode1 ) return false;
2075 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2076 if ( !theNode2 ) return false;
2082 const SMESHDS_Mesh* myMesh;
2087 //=======================================================================
2088 //function : TriToQuad
2089 //purpose : Fuse neighbour triangles into quadrangles.
2090 // theCrit is used to select a neighbour to fuse with.
2091 // theMaxAngle is a max angle between element normals at which
2092 // fusion is still performed.
2093 //=======================================================================
2095 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2096 SMESH::Controls::NumericalFunctorPtr theCrit,
2097 const double theMaxAngle)
2099 myLastCreatedElems.Clear();
2100 myLastCreatedNodes.Clear();
2102 MESSAGE( "::TriToQuad()" );
2104 if ( !theCrit.get() )
2107 SMESHDS_Mesh * aMesh = GetMeshDS();
2109 // Prepare data for algo: build
2110 // 1. map of elements with their linkIDs
2111 // 2. map of linkIDs with their elements
2113 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2114 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2115 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2116 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2118 TIDSortedElemSet::iterator itElem;
2119 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2120 const SMDS_MeshElement* elem = *itElem;
2121 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2122 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2123 if(!IsTria) continue;
2125 // retrieve element nodes
2126 const SMDS_MeshNode* aNodes [4];
2127 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2130 aNodes[ i++ ] = cast2Node( itN->next() );
2131 aNodes[ 3 ] = aNodes[ 0 ];
2134 for ( i = 0; i < 3; i++ ) {
2135 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2136 // check if elements sharing a link can be fused
2137 itLE = mapLi_listEl.find( link );
2138 if ( itLE != mapLi_listEl.end() ) {
2139 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2141 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2142 //if ( FindShape( elem ) != FindShape( elem2 ))
2143 // continue; // do not fuse triangles laying on different shapes
2144 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2145 continue; // avoid making badly shaped quads
2146 (*itLE).second.push_back( elem );
2149 mapLi_listEl[ link ].push_back( elem );
2151 mapEl_setLi [ elem ].insert( link );
2154 // Clean the maps from the links shared by a sole element, ie
2155 // links to which only one element is bound in mapLi_listEl
2157 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2158 int nbElems = (*itLE).second.size();
2159 if ( nbElems < 2 ) {
2160 const SMDS_MeshElement* elem = (*itLE).second.front();
2161 SMESH_TLink link = (*itLE).first;
2162 mapEl_setLi[ elem ].erase( link );
2163 if ( mapEl_setLi[ elem ].empty() )
2164 mapEl_setLi.erase( elem );
2168 // Algo: fuse triangles into quadrangles
2170 while ( ! mapEl_setLi.empty() ) {
2171 // Look for the start element:
2172 // the element having the least nb of shared links
2173 const SMDS_MeshElement* startElem = 0;
2175 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2176 int nbLinks = (*itEL).second.size();
2177 if ( nbLinks < minNbLinks ) {
2178 startElem = (*itEL).first;
2179 minNbLinks = nbLinks;
2180 if ( minNbLinks == 1 )
2185 // search elements to fuse starting from startElem or links of elements
2186 // fused earlyer - startLinks
2187 list< SMESH_TLink > startLinks;
2188 while ( startElem || !startLinks.empty() ) {
2189 while ( !startElem && !startLinks.empty() ) {
2190 // Get an element to start, by a link
2191 SMESH_TLink linkId = startLinks.front();
2192 startLinks.pop_front();
2193 itLE = mapLi_listEl.find( linkId );
2194 if ( itLE != mapLi_listEl.end() ) {
2195 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2196 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2197 for ( ; itE != listElem.end() ; itE++ )
2198 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2200 mapLi_listEl.erase( itLE );
2205 // Get candidates to be fused
2206 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2207 const SMESH_TLink *link12, *link13;
2209 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2210 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2211 ASSERT( !setLi.empty() );
2212 set< SMESH_TLink >::iterator itLi;
2213 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2215 const SMESH_TLink & link = (*itLi);
2216 itLE = mapLi_listEl.find( link );
2217 if ( itLE == mapLi_listEl.end() )
2220 const SMDS_MeshElement* elem = (*itLE).second.front();
2222 elem = (*itLE).second.back();
2223 mapLi_listEl.erase( itLE );
2224 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2235 // add other links of elem to list of links to re-start from
2236 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2237 set< SMESH_TLink >::iterator it;
2238 for ( it = links.begin(); it != links.end(); it++ ) {
2239 const SMESH_TLink& link2 = (*it);
2240 if ( link2 != link )
2241 startLinks.push_back( link2 );
2245 // Get nodes of possible quadrangles
2246 const SMDS_MeshNode *n12 [4], *n13 [4];
2247 bool Ok12 = false, Ok13 = false;
2248 const SMDS_MeshNode *linkNode1, *linkNode2;
2250 linkNode1 = link12->first;
2251 linkNode2 = link12->second;
2252 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2256 linkNode1 = link13->first;
2257 linkNode2 = link13->second;
2258 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2262 // Choose a pair to fuse
2263 if ( Ok12 && Ok13 ) {
2264 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2265 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2266 double aBadRate12 = getBadRate( &quad12, theCrit );
2267 double aBadRate13 = getBadRate( &quad13, theCrit );
2268 if ( aBadRate13 < aBadRate12 )
2275 // and remove fused elems and removed links from the maps
2276 mapEl_setLi.erase( tr1 );
2278 mapEl_setLi.erase( tr2 );
2279 mapLi_listEl.erase( *link12 );
2280 if(tr1->NbNodes()==3) {
2281 const SMDS_MeshElement* newElem = 0;
2282 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2283 myLastCreatedElems.Append(newElem);
2284 AddToSameGroups( newElem, tr1, aMesh );
2285 int aShapeId = tr1->getshapeId();
2288 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2290 aMesh->RemoveElement( tr1 );
2291 aMesh->RemoveElement( tr2 );
2294 const SMDS_MeshNode* N1 [6];
2295 const SMDS_MeshNode* N2 [6];
2296 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2297 // now we receive following N1 and N2 (using numeration as above image)
2298 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2299 // i.e. first nodes from both arrays determ new diagonal
2300 const SMDS_MeshNode* aNodes[8];
2309 const SMDS_MeshElement* newElem = 0;
2310 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2311 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2312 myLastCreatedElems.Append(newElem);
2313 AddToSameGroups( newElem, tr1, aMesh );
2314 int aShapeId = tr1->getshapeId();
2317 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2319 aMesh->RemoveElement( tr1 );
2320 aMesh->RemoveElement( tr2 );
2321 // remove middle node (9)
2322 GetMeshDS()->RemoveNode( N1[4] );
2326 mapEl_setLi.erase( tr3 );
2327 mapLi_listEl.erase( *link13 );
2328 if(tr1->NbNodes()==3) {
2329 const SMDS_MeshElement* newElem = 0;
2330 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2331 myLastCreatedElems.Append(newElem);
2332 AddToSameGroups( newElem, tr1, aMesh );
2333 int aShapeId = tr1->getshapeId();
2336 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2338 aMesh->RemoveElement( tr1 );
2339 aMesh->RemoveElement( tr3 );
2342 const SMDS_MeshNode* N1 [6];
2343 const SMDS_MeshNode* N2 [6];
2344 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2345 // now we receive following N1 and N2 (using numeration as above image)
2346 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2347 // i.e. first nodes from both arrays determ new diagonal
2348 const SMDS_MeshNode* aNodes[8];
2357 const SMDS_MeshElement* newElem = 0;
2358 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2359 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2360 myLastCreatedElems.Append(newElem);
2361 AddToSameGroups( newElem, tr1, aMesh );
2362 int aShapeId = tr1->getshapeId();
2365 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2367 aMesh->RemoveElement( tr1 );
2368 aMesh->RemoveElement( tr3 );
2369 // remove middle node (9)
2370 GetMeshDS()->RemoveNode( N1[4] );
2374 // Next element to fuse: the rejected one
2376 startElem = Ok12 ? tr3 : tr2;
2378 } // if ( startElem )
2379 } // while ( startElem || !startLinks.empty() )
2380 } // while ( ! mapEl_setLi.empty() )
2386 /*#define DUMPSO(txt) \
2387 // cout << txt << endl;
2388 //=============================================================================
2392 //=============================================================================
2393 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2397 int tmp = idNodes[ i1 ];
2398 idNodes[ i1 ] = idNodes[ i2 ];
2399 idNodes[ i2 ] = tmp;
2400 gp_Pnt Ptmp = P[ i1 ];
2403 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2406 //=======================================================================
2407 //function : SortQuadNodes
2408 //purpose : Set 4 nodes of a quadrangle face in a good order.
2409 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2411 //=======================================================================
2413 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2418 for ( i = 0; i < 4; i++ ) {
2419 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2421 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2424 gp_Vec V1(P[0], P[1]);
2425 gp_Vec V2(P[0], P[2]);
2426 gp_Vec V3(P[0], P[3]);
2428 gp_Vec Cross1 = V1 ^ V2;
2429 gp_Vec Cross2 = V2 ^ V3;
2432 if (Cross1.Dot(Cross2) < 0)
2437 if (Cross1.Dot(Cross2) < 0)
2441 swap ( i, i + 1, idNodes, P );
2443 // for ( int ii = 0; ii < 4; ii++ ) {
2444 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2445 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2451 //=======================================================================
2452 //function : SortHexaNodes
2453 //purpose : Set 8 nodes of a hexahedron in a good order.
2454 // Return success status
2455 //=======================================================================
2457 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2462 DUMPSO( "INPUT: ========================================");
2463 for ( i = 0; i < 8; i++ ) {
2464 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2465 if ( !n ) return false;
2466 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2467 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2469 DUMPSO( "========================================");
2472 set<int> faceNodes; // ids of bottom face nodes, to be found
2473 set<int> checkedId1; // ids of tried 2-nd nodes
2474 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2475 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2476 int iMin, iLoop1 = 0;
2478 // Loop to try the 2-nd nodes
2480 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2482 // Find not checked 2-nd node
2483 for ( i = 1; i < 8; i++ )
2484 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2485 int id1 = idNodes[i];
2486 swap ( 1, i, idNodes, P );
2487 checkedId1.insert ( id1 );
2491 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2492 // ie that all but meybe one (id3 which is on the same face) nodes
2493 // lay on the same side from the triangle plane.
2495 bool manyInPlane = false; // more than 4 nodes lay in plane
2497 while ( ++iLoop2 < 6 ) {
2499 // get 1-2-3 plane coeffs
2500 Standard_Real A, B, C, D;
2501 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2502 if ( N.SquareMagnitude() > gp::Resolution() )
2504 gp_Pln pln ( P[0], N );
2505 pln.Coefficients( A, B, C, D );
2507 // find the node (iMin) closest to pln
2508 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2510 for ( i = 3; i < 8; i++ ) {
2511 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2512 if ( fabs( dist[i] ) < minDist ) {
2513 minDist = fabs( dist[i] );
2516 if ( fabs( dist[i] ) <= tol )
2517 idInPln.insert( idNodes[i] );
2520 // there should not be more than 4 nodes in bottom plane
2521 if ( idInPln.size() > 1 )
2523 DUMPSO( "### idInPln.size() = " << idInPln.size());
2524 // idInPlane does not contain the first 3 nodes
2525 if ( manyInPlane || idInPln.size() == 5)
2526 return false; // all nodes in one plane
2529 // set the 1-st node to be not in plane
2530 for ( i = 3; i < 8; i++ ) {
2531 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2532 DUMPSO( "### Reset 0-th node");
2533 swap( 0, i, idNodes, P );
2538 // reset to re-check second nodes
2539 leastDist = DBL_MAX;
2543 break; // from iLoop2;
2546 // check that the other 4 nodes are on the same side
2547 bool sameSide = true;
2548 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2549 for ( i = 3; sameSide && i < 8; i++ ) {
2551 sameSide = ( isNeg == dist[i] <= 0.);
2554 // keep best solution
2555 if ( sameSide && minDist < leastDist ) {
2556 leastDist = minDist;
2558 faceNodes.insert( idNodes[ 1 ] );
2559 faceNodes.insert( idNodes[ 2 ] );
2560 faceNodes.insert( idNodes[ iMin ] );
2561 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2562 << " leastDist = " << leastDist);
2563 if ( leastDist <= DBL_MIN )
2568 // set next 3-d node to check
2569 int iNext = 2 + iLoop2;
2571 DUMPSO( "Try 2-nd");
2572 swap ( 2, iNext, idNodes, P );
2574 } // while ( iLoop2 < 6 )
2577 if ( faceNodes.empty() ) return false;
2579 // Put the faceNodes in proper places
2580 for ( i = 4; i < 8; i++ ) {
2581 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2582 // find a place to put
2584 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2586 DUMPSO( "Set faceNodes");
2587 swap ( iTo, i, idNodes, P );
2592 // Set nodes of the found bottom face in good order
2593 DUMPSO( " Found bottom face: ");
2594 i = SortQuadNodes( theMesh, idNodes );
2596 gp_Pnt Ptmp = P[ i ];
2601 // for ( int ii = 0; ii < 4; ii++ ) {
2602 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2603 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2606 // Gravity center of the top and bottom faces
2607 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2608 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2610 // Get direction from the bottom to the top face
2611 gp_Vec upDir ( aGCb, aGCt );
2612 Standard_Real upDirSize = upDir.Magnitude();
2613 if ( upDirSize <= gp::Resolution() ) return false;
2616 // Assure that the bottom face normal points up
2617 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2618 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2619 if ( Nb.Dot( upDir ) < 0 ) {
2620 DUMPSO( "Reverse bottom face");
2621 swap( 1, 3, idNodes, P );
2624 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2625 Standard_Real minDist = DBL_MAX;
2626 for ( i = 4; i < 8; i++ ) {
2627 // projection of P[i] to the plane defined by P[0] and upDir
2628 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2629 Standard_Real sqDist = P[0].SquareDistance( Pp );
2630 if ( sqDist < minDist ) {
2635 DUMPSO( "Set 4-th");
2636 swap ( 4, iMin, idNodes, P );
2638 // Set nodes of the top face in good order
2639 DUMPSO( "Sort top face");
2640 i = SortQuadNodes( theMesh, &idNodes[4] );
2643 gp_Pnt Ptmp = P[ i ];
2648 // Assure that direction of the top face normal is from the bottom face
2649 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2650 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2651 if ( Nt.Dot( upDir ) < 0 ) {
2652 DUMPSO( "Reverse top face");
2653 swap( 5, 7, idNodes, P );
2656 // DUMPSO( "OUTPUT: ========================================");
2657 // for ( i = 0; i < 8; i++ ) {
2658 // float *p = ugrid->GetPoint(idNodes[i]);
2659 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2665 //================================================================================
2667 * \brief Return nodes linked to the given one
2668 * \param theNode - the node
2669 * \param linkedNodes - the found nodes
2670 * \param type - the type of elements to check
2672 * Medium nodes are ignored
2674 //================================================================================
2676 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2677 TIDSortedElemSet & linkedNodes,
2678 SMDSAbs_ElementType type )
2680 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2681 while ( elemIt->more() )
2683 const SMDS_MeshElement* elem = elemIt->next();
2684 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2685 if ( elem->GetType() == SMDSAbs_Volume )
2687 SMDS_VolumeTool vol( elem );
2688 while ( nodeIt->more() ) {
2689 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2690 if ( theNode != n && vol.IsLinked( theNode, n ))
2691 linkedNodes.insert( n );
2696 for ( int i = 0; nodeIt->more(); ++i ) {
2697 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2698 if ( n == theNode ) {
2699 int iBefore = i - 1;
2701 if ( elem->IsQuadratic() ) {
2702 int nb = elem->NbNodes() / 2;
2703 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2704 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2706 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2707 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2714 //=======================================================================
2715 //function : laplacianSmooth
2716 //purpose : pulls theNode toward the center of surrounding nodes directly
2717 // connected to that node along an element edge
2718 //=======================================================================
2720 void laplacianSmooth(const SMDS_MeshNode* theNode,
2721 const Handle(Geom_Surface)& theSurface,
2722 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2724 // find surrounding nodes
2726 TIDSortedElemSet nodeSet;
2727 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2729 // compute new coodrs
2731 double coord[] = { 0., 0., 0. };
2732 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2733 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2734 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2735 if ( theSurface.IsNull() ) { // smooth in 3D
2736 coord[0] += node->X();
2737 coord[1] += node->Y();
2738 coord[2] += node->Z();
2740 else { // smooth in 2D
2741 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2742 gp_XY* uv = theUVMap[ node ];
2743 coord[0] += uv->X();
2744 coord[1] += uv->Y();
2747 int nbNodes = nodeSet.size();
2750 coord[0] /= nbNodes;
2751 coord[1] /= nbNodes;
2753 if ( !theSurface.IsNull() ) {
2754 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2755 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2756 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2762 coord[2] /= nbNodes;
2766 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2769 //=======================================================================
2770 //function : centroidalSmooth
2771 //purpose : pulls theNode toward the element-area-weighted centroid of the
2772 // surrounding elements
2773 //=======================================================================
2775 void centroidalSmooth(const SMDS_MeshNode* theNode,
2776 const Handle(Geom_Surface)& theSurface,
2777 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2779 gp_XYZ aNewXYZ(0.,0.,0.);
2780 SMESH::Controls::Area anAreaFunc;
2781 double totalArea = 0.;
2786 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2787 while ( elemIt->more() )
2789 const SMDS_MeshElement* elem = elemIt->next();
2792 gp_XYZ elemCenter(0.,0.,0.);
2793 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2794 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2795 int nn = elem->NbNodes();
2796 if(elem->IsQuadratic()) nn = nn/2;
2798 //while ( itN->more() ) {
2800 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2802 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2803 aNodePoints.push_back( aP );
2804 if ( !theSurface.IsNull() ) { // smooth in 2D
2805 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2806 gp_XY* uv = theUVMap[ aNode ];
2807 aP.SetCoord( uv->X(), uv->Y(), 0. );
2811 double elemArea = anAreaFunc.GetValue( aNodePoints );
2812 totalArea += elemArea;
2814 aNewXYZ += elemCenter * elemArea;
2816 aNewXYZ /= totalArea;
2817 if ( !theSurface.IsNull() ) {
2818 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2819 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2824 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2827 //=======================================================================
2828 //function : getClosestUV
2829 //purpose : return UV of closest projection
2830 //=======================================================================
2832 static bool getClosestUV (Extrema_GenExtPS& projector,
2833 const gp_Pnt& point,
2836 projector.Perform( point );
2837 if ( projector.IsDone() ) {
2838 double u, v, minVal = DBL_MAX;
2839 for ( int i = projector.NbExt(); i > 0; i-- )
2840 if ( projector.Value( i ) < minVal ) {
2841 minVal = projector.Value( i );
2842 projector.Point( i ).Parameter( u, v );
2844 result.SetCoord( u, v );
2850 //=======================================================================
2852 //purpose : Smooth theElements during theNbIterations or until a worst
2853 // element has aspect ratio <= theTgtAspectRatio.
2854 // Aspect Ratio varies in range [1.0, inf].
2855 // If theElements is empty, the whole mesh is smoothed.
2856 // theFixedNodes contains additionally fixed nodes. Nodes built
2857 // on edges and boundary nodes are always fixed.
2858 //=======================================================================
2860 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2861 set<const SMDS_MeshNode*> & theFixedNodes,
2862 const SmoothMethod theSmoothMethod,
2863 const int theNbIterations,
2864 double theTgtAspectRatio,
2867 myLastCreatedElems.Clear();
2868 myLastCreatedNodes.Clear();
2870 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2872 if ( theTgtAspectRatio < 1.0 )
2873 theTgtAspectRatio = 1.0;
2875 const double disttol = 1.e-16;
2877 SMESH::Controls::AspectRatio aQualityFunc;
2879 SMESHDS_Mesh* aMesh = GetMeshDS();
2881 if ( theElems.empty() ) {
2882 // add all faces to theElems
2883 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2884 while ( fIt->more() ) {
2885 const SMDS_MeshElement* face = fIt->next();
2886 theElems.insert( face );
2889 // get all face ids theElems are on
2890 set< int > faceIdSet;
2891 TIDSortedElemSet::iterator itElem;
2893 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2894 int fId = FindShape( *itElem );
2895 // check that corresponding submesh exists and a shape is face
2897 faceIdSet.find( fId ) == faceIdSet.end() &&
2898 aMesh->MeshElements( fId )) {
2899 TopoDS_Shape F = aMesh->IndexToShape( fId );
2900 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2901 faceIdSet.insert( fId );
2904 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2906 // ===============================================
2907 // smooth elements on each TopoDS_Face separately
2908 // ===============================================
2910 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2911 for ( ; fId != faceIdSet.rend(); ++fId ) {
2912 // get face surface and submesh
2913 Handle(Geom_Surface) surface;
2914 SMESHDS_SubMesh* faceSubMesh = 0;
2916 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2917 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2918 bool isUPeriodic = false, isVPeriodic = false;
2920 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2921 surface = BRep_Tool::Surface( face );
2922 faceSubMesh = aMesh->MeshElements( *fId );
2923 fToler2 = BRep_Tool::Tolerance( face );
2924 fToler2 *= fToler2 * 10.;
2925 isUPeriodic = surface->IsUPeriodic();
2927 vPeriod = surface->UPeriod();
2928 isVPeriodic = surface->IsVPeriodic();
2930 uPeriod = surface->VPeriod();
2931 surface->Bounds( u1, u2, v1, v2 );
2933 // ---------------------------------------------------------
2934 // for elements on a face, find movable and fixed nodes and
2935 // compute UV for them
2936 // ---------------------------------------------------------
2937 bool checkBoundaryNodes = false;
2938 bool isQuadratic = false;
2939 set<const SMDS_MeshNode*> setMovableNodes;
2940 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2941 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2942 list< const SMDS_MeshElement* > elemsOnFace;
2944 Extrema_GenExtPS projector;
2945 GeomAdaptor_Surface surfAdaptor;
2946 if ( !surface.IsNull() ) {
2947 surfAdaptor.Load( surface );
2948 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2950 int nbElemOnFace = 0;
2951 itElem = theElems.begin();
2952 // loop on not yet smoothed elements: look for elems on a face
2953 while ( itElem != theElems.end() ) {
2954 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2955 break; // all elements found
2957 const SMDS_MeshElement* elem = *itElem;
2958 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2959 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2963 elemsOnFace.push_back( elem );
2964 theElems.erase( itElem++ );
2968 isQuadratic = elem->IsQuadratic();
2970 // get movable nodes of elem
2971 const SMDS_MeshNode* node;
2972 SMDS_TypeOfPosition posType;
2973 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2974 int nn = 0, nbn = elem->NbNodes();
2975 if(elem->IsQuadratic())
2977 while ( nn++ < nbn ) {
2978 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2979 const SMDS_PositionPtr& pos = node->GetPosition();
2980 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2981 if (posType != SMDS_TOP_EDGE &&
2982 posType != SMDS_TOP_VERTEX &&
2983 theFixedNodes.find( node ) == theFixedNodes.end())
2985 // check if all faces around the node are on faceSubMesh
2986 // because a node on edge may be bound to face
2987 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2989 if ( faceSubMesh ) {
2990 while ( eIt->more() && all ) {
2991 const SMDS_MeshElement* e = eIt->next();
2992 all = faceSubMesh->Contains( e );
2996 setMovableNodes.insert( node );
2998 checkBoundaryNodes = true;
3000 if ( posType == SMDS_TOP_3DSPACE )
3001 checkBoundaryNodes = true;
3004 if ( surface.IsNull() )
3007 // get nodes to check UV
3008 list< const SMDS_MeshNode* > uvCheckNodes;
3009 itN = elem->nodesIterator();
3010 nn = 0; nbn = elem->NbNodes();
3011 if(elem->IsQuadratic())
3013 while ( nn++ < nbn ) {
3014 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3015 if ( uvMap.find( node ) == uvMap.end() )
3016 uvCheckNodes.push_back( node );
3017 // add nodes of elems sharing node
3018 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3019 // while ( eIt->more() ) {
3020 // const SMDS_MeshElement* e = eIt->next();
3021 // if ( e != elem ) {
3022 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3023 // while ( nIt->more() ) {
3024 // const SMDS_MeshNode* n =
3025 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3026 // if ( uvMap.find( n ) == uvMap.end() )
3027 // uvCheckNodes.push_back( n );
3033 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3034 for ( ; n != uvCheckNodes.end(); ++n ) {
3037 const SMDS_PositionPtr& pos = node->GetPosition();
3038 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3040 switch ( posType ) {
3041 case SMDS_TOP_FACE: {
3042 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3043 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3046 case SMDS_TOP_EDGE: {
3047 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3048 Handle(Geom2d_Curve) pcurve;
3049 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3050 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3051 if ( !pcurve.IsNull() ) {
3052 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3053 uv = pcurve->Value( u ).XY();
3057 case SMDS_TOP_VERTEX: {
3058 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3059 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3060 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3065 // check existing UV
3066 bool project = true;
3067 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3068 double dist1 = DBL_MAX, dist2 = 0;
3069 if ( posType != SMDS_TOP_3DSPACE ) {
3070 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3071 project = dist1 > fToler2;
3073 if ( project ) { // compute new UV
3075 if ( !getClosestUV( projector, pNode, newUV )) {
3076 MESSAGE("Node Projection Failed " << node);
3080 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3082 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3084 if ( posType != SMDS_TOP_3DSPACE )
3085 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3086 if ( dist2 < dist1 )
3090 // store UV in the map
3091 listUV.push_back( uv );
3092 uvMap.insert( make_pair( node, &listUV.back() ));
3094 } // loop on not yet smoothed elements
3096 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3097 checkBoundaryNodes = true;
3099 // fix nodes on mesh boundary
3101 if ( checkBoundaryNodes ) {
3102 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3103 map< NLink, int >::iterator link_nb;
3104 // put all elements links to linkNbMap
3105 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3106 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3107 const SMDS_MeshElement* elem = (*elemIt);
3108 int nbn = elem->NbNodes();
3109 if(elem->IsQuadratic())
3111 // loop on elem links: insert them in linkNbMap
3112 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3113 for ( int iN = 0; iN < nbn; ++iN ) {
3114 curNode = elem->GetNode( iN );
3116 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3117 else link = make_pair( prevNode , curNode );
3119 link_nb = linkNbMap.find( link );
3120 if ( link_nb == linkNbMap.end() )
3121 linkNbMap.insert( make_pair ( link, 1 ));
3126 // remove nodes that are in links encountered only once from setMovableNodes
3127 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3128 if ( link_nb->second == 1 ) {
3129 setMovableNodes.erase( link_nb->first.first );
3130 setMovableNodes.erase( link_nb->first.second );
3135 // -----------------------------------------------------
3136 // for nodes on seam edge, compute one more UV ( uvMap2 );
3137 // find movable nodes linked to nodes on seam and which
3138 // are to be smoothed using the second UV ( uvMap2 )
3139 // -----------------------------------------------------
3141 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3142 if ( !surface.IsNull() ) {
3143 TopExp_Explorer eExp( face, TopAbs_EDGE );
3144 for ( ; eExp.More(); eExp.Next() ) {
3145 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3146 if ( !BRep_Tool::IsClosed( edge, face ))
3148 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3149 if ( !sm ) continue;
3150 // find out which parameter varies for a node on seam
3153 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3154 if ( pcurve.IsNull() ) continue;
3155 uv1 = pcurve->Value( f );
3157 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3158 if ( pcurve.IsNull() ) continue;
3159 uv2 = pcurve->Value( f );
3160 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3162 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3163 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3165 // get nodes on seam and its vertices
3166 list< const SMDS_MeshNode* > seamNodes;
3167 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3168 while ( nSeamIt->more() ) {
3169 const SMDS_MeshNode* node = nSeamIt->next();
3170 if ( !isQuadratic || !IsMedium( node ))
3171 seamNodes.push_back( node );
3173 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3174 for ( ; vExp.More(); vExp.Next() ) {
3175 sm = aMesh->MeshElements( vExp.Current() );
3177 nSeamIt = sm->GetNodes();
3178 while ( nSeamIt->more() )
3179 seamNodes.push_back( nSeamIt->next() );
3182 // loop on nodes on seam
3183 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3184 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3185 const SMDS_MeshNode* nSeam = *noSeIt;
3186 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3187 if ( n_uv == uvMap.end() )
3190 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3191 // set the second UV
3192 listUV.push_back( *n_uv->second );
3193 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3194 if ( uvMap2.empty() )
3195 uvMap2 = uvMap; // copy the uvMap contents
3196 uvMap2[ nSeam ] = &listUV.back();
3198 // collect movable nodes linked to ones on seam in nodesNearSeam
3199 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3200 while ( eIt->more() ) {
3201 const SMDS_MeshElement* e = eIt->next();
3202 int nbUseMap1 = 0, nbUseMap2 = 0;
3203 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3204 int nn = 0, nbn = e->NbNodes();
3205 if(e->IsQuadratic()) nbn = nbn/2;
3206 while ( nn++ < nbn )
3208 const SMDS_MeshNode* n =
3209 static_cast<const SMDS_MeshNode*>( nIt->next() );
3211 setMovableNodes.find( n ) == setMovableNodes.end() )
3213 // add only nodes being closer to uv2 than to uv1
3214 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3215 0.5 * ( n->Y() + nSeam->Y() ),
3216 0.5 * ( n->Z() + nSeam->Z() ));
3218 getClosestUV( projector, pMid, uv );
3219 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3220 nodesNearSeam.insert( n );
3226 // for centroidalSmooth all element nodes must
3227 // be on one side of a seam
3228 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3229 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3231 while ( nn++ < nbn ) {
3232 const SMDS_MeshNode* n =
3233 static_cast<const SMDS_MeshNode*>( nIt->next() );
3234 setMovableNodes.erase( n );
3238 } // loop on nodes on seam
3239 } // loop on edge of a face
3240 } // if ( !face.IsNull() )
3242 if ( setMovableNodes.empty() ) {
3243 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3244 continue; // goto next face
3252 double maxRatio = -1., maxDisplacement = -1.;
3253 set<const SMDS_MeshNode*>::iterator nodeToMove;
3254 for ( it = 0; it < theNbIterations; it++ ) {
3255 maxDisplacement = 0.;
3256 nodeToMove = setMovableNodes.begin();
3257 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3258 const SMDS_MeshNode* node = (*nodeToMove);
3259 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3262 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3263 if ( theSmoothMethod == LAPLACIAN )
3264 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3266 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3268 // node displacement
3269 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3270 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3271 if ( aDispl > maxDisplacement )
3272 maxDisplacement = aDispl;
3274 // no node movement => exit
3275 //if ( maxDisplacement < 1.e-16 ) {
3276 if ( maxDisplacement < disttol ) {
3277 MESSAGE("-- no node movement --");
3281 // check elements quality
3283 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3284 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3285 const SMDS_MeshElement* elem = (*elemIt);
3286 if ( !elem || elem->GetType() != SMDSAbs_Face )
3288 SMESH::Controls::TSequenceOfXYZ aPoints;
3289 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3290 double aValue = aQualityFunc.GetValue( aPoints );
3291 if ( aValue > maxRatio )
3295 if ( maxRatio <= theTgtAspectRatio ) {
3296 MESSAGE("-- quality achived --");
3299 if (it+1 == theNbIterations) {
3300 MESSAGE("-- Iteration limit exceeded --");
3302 } // smoothing iterations
3304 MESSAGE(" Face id: " << *fId <<
3305 " Nb iterstions: " << it <<
3306 " Displacement: " << maxDisplacement <<
3307 " Aspect Ratio " << maxRatio);
3309 // ---------------------------------------
3310 // new nodes positions are computed,
3311 // record movement in DS and set new UV
3312 // ---------------------------------------
3313 nodeToMove = setMovableNodes.begin();
3314 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3315 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3316 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3317 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3318 if ( node_uv != uvMap.end() ) {
3319 gp_XY* uv = node_uv->second;
3321 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3325 // move medium nodes of quadratic elements
3328 SMESH_MesherHelper helper( *GetMesh() );
3329 if ( !face.IsNull() )
3330 helper.SetSubShape( face );
3331 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3332 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3333 const SMDS_VtkFace* QF =
3334 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3335 if(QF && QF->IsQuadratic()) {
3336 vector<const SMDS_MeshNode*> Ns;
3337 Ns.reserve(QF->NbNodes()+1);
3338 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3339 while ( anIter->more() )
3340 Ns.push_back( cast2Node(anIter->next()) );
3341 Ns.push_back( Ns[0] );
3343 for(int i=0; i<QF->NbNodes(); i=i+2) {
3344 if ( !surface.IsNull() ) {
3345 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3346 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3347 gp_XY uv = ( uv1 + uv2 ) / 2.;
3348 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3349 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3352 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3353 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3354 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3356 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3357 fabs( Ns[i+1]->Y() - y ) > disttol ||
3358 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3359 // we have to move i+1 node
3360 aMesh->MoveNode( Ns[i+1], x, y, z );
3367 } // loop on face ids
3371 //=======================================================================
3372 //function : isReverse
3373 //purpose : Return true if normal of prevNodes is not co-directied with
3374 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3375 // iNotSame is where prevNodes and nextNodes are different
3376 //=======================================================================
3378 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3379 vector<const SMDS_MeshNode*> nextNodes,
3383 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3384 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3386 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3387 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3388 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3389 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3391 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3392 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3393 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3394 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3396 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3398 return (vA ^ vB) * vN < 0.0;
3401 //=======================================================================
3403 * \brief Create elements by sweeping an element
3404 * \param elem - element to sweep
3405 * \param newNodesItVec - nodes generated from each node of the element
3406 * \param newElems - generated elements
3407 * \param nbSteps - number of sweeping steps
3408 * \param srcElements - to append elem for each generated element
3410 //=======================================================================
3412 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3413 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3414 list<const SMDS_MeshElement*>& newElems,
3416 SMESH_SequenceOfElemPtr& srcElements)
3418 //MESSAGE("sweepElement " << nbSteps);
3419 SMESHDS_Mesh* aMesh = GetMeshDS();
3421 // Loop on elem nodes:
3422 // find new nodes and detect same nodes indices
3423 int nbNodes = elem->NbNodes();
3424 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3425 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3426 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3427 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3429 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3430 vector<int> sames(nbNodes);
3431 vector<bool> issimple(nbNodes);
3433 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3434 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3435 const SMDS_MeshNode* node = nnIt->first;
3436 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3437 if ( listNewNodes.empty() ) {
3441 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3443 itNN[ iNode ] = listNewNodes.begin();
3444 prevNod[ iNode ] = node;
3445 nextNod[ iNode ] = listNewNodes.front();
3446 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3447 if ( prevNod[ iNode ] != nextNod [ iNode ])
3448 iNotSameNode = iNode;
3452 sames[nbSame++] = iNode;
3457 //cerr<<" nbSame = "<<nbSame<<endl;
3458 if ( nbSame == nbNodes || nbSame > 2) {
3459 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3460 //INFOS( " Too many same nodes of element " << elem->GetID() );
3464 // if( elem->IsQuadratic() && nbSame>0 ) {
3465 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3469 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3470 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3472 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3473 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3474 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3478 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3479 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3480 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3481 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3483 // check element orientation
3485 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3486 //MESSAGE("Reversed elem " << elem );
3490 std::swap( iBeforeSame, iAfterSame );
3493 // make new elements
3494 const SMDS_MeshElement* lastElem = elem;
3495 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3497 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3498 if(issimple[iNode]) {
3499 nextNod[ iNode ] = *itNN[ iNode ];
3503 if( elem->GetType()==SMDSAbs_Node ) {
3504 // we have to use two nodes
3505 midlNod[ iNode ] = *itNN[ iNode ];
3507 nextNod[ iNode ] = *itNN[ iNode ];
3510 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3511 // we have to use each second node
3513 nextNod[ iNode ] = *itNN[ iNode ];
3517 // we have to use two nodes
3518 midlNod[ iNode ] = *itNN[ iNode ];
3520 nextNod[ iNode ] = *itNN[ iNode ];
3525 SMDS_MeshElement* aNewElem = 0;
3526 if(!elem->IsPoly()) {
3527 switch ( nbNodes ) {
3531 if ( nbSame == 0 ) {
3533 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3535 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3541 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3542 nextNod[ 1 ], nextNod[ 0 ] );
3544 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3545 nextNod[ iNotSameNode ] );
3549 case 3: { // TRIANGLE or quadratic edge
3550 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3552 if ( nbSame == 0 ) // --- pentahedron
3553 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3554 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3556 else if ( nbSame == 1 ) // --- pyramid
3557 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3558 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3559 nextNod[ iSameNode ]);
3561 else // 2 same nodes: --- tetrahedron
3562 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3563 nextNod[ iNotSameNode ]);
3565 else { // quadratic edge
3566 if(nbSame==0) { // quadratic quadrangle
3567 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3568 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3570 else if(nbSame==1) { // quadratic triangle
3572 return; // medium node on axis
3574 else if(sames[0]==0) {
3575 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3576 nextNod[2], midlNod[1], prevNod[2]);
3578 else { // sames[0]==1
3579 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3580 midlNod[0], nextNod[2], prevNod[2]);
3589 case 4: { // QUADRANGLE
3591 if ( nbSame == 0 ) // --- hexahedron
3592 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3593 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3595 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3596 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3597 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3598 nextNod[ iSameNode ]);
3599 newElems.push_back( aNewElem );
3600 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3601 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3602 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3604 else if ( nbSame == 2 ) { // pentahedron
3605 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3606 // iBeforeSame is same too
3607 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3608 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3609 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3611 // iAfterSame is same too
3612 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3613 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3614 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3618 case 6: { // quadratic triangle
3619 // create pentahedron with 15 nodes
3621 if(i0>0) { // reversed case
3622 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3623 nextNod[0], nextNod[2], nextNod[1],
3624 prevNod[5], prevNod[4], prevNod[3],
3625 nextNod[5], nextNod[4], nextNod[3],
3626 midlNod[0], midlNod[2], midlNod[1]);
3628 else { // not reversed case
3629 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3630 nextNod[0], nextNod[1], nextNod[2],
3631 prevNod[3], prevNod[4], prevNod[5],
3632 nextNod[3], nextNod[4], nextNod[5],
3633 midlNod[0], midlNod[1], midlNod[2]);
3636 else if(nbSame==1) {
3637 // 2d order pyramid of 13 nodes
3638 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3639 // int n12,int n23,int n34,int n41,
3640 // int n15,int n25,int n35,int n45, int ID);
3642 int n1,n4,n41,n15,n45;
3643 if(i0>0) { // reversed case
3644 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3645 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3651 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3652 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3657 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3658 nextNod[n4], prevNod[n4], prevNod[n5],
3659 midlNod[n1], nextNod[n41],
3660 midlNod[n4], prevNod[n41],
3661 prevNod[n15], nextNod[n15],
3662 nextNod[n45], prevNod[n45]);
3664 else if(nbSame==2) {
3665 // 2d order tetrahedron of 10 nodes
3666 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3667 // int n12,int n23,int n31,
3668 // int n14,int n24,int n34, int ID);
3669 int n1 = iNotSameNode;
3670 int n2,n3,n12,n23,n31;
3671 if(i0>0) { // reversed case
3672 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3673 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3679 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3680 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3685 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3686 prevNod[n12], prevNod[n23], prevNod[n31],
3687 midlNod[n1], nextNod[n12], nextNod[n31]);
3691 case 8: { // quadratic quadrangle
3693 // create hexahedron with 20 nodes
3694 if(i0>0) { // reversed case
3695 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3696 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3697 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3698 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3699 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3701 else { // not reversed case
3702 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3703 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3704 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3705 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3706 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3709 else if(nbSame==1) {
3710 // --- pyramid + pentahedron - can not be created since it is needed
3711 // additional middle node ot the center of face
3712 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3715 else if(nbSame==2) {
3716 // 2d order Pentahedron with 15 nodes
3717 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3718 // int n12,int n23,int n31,int n45,int n56,int n64,
3719 // int n14,int n25,int n36, int ID);
3721 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3722 // iBeforeSame is same too
3729 // iAfterSame is same too
3735 int n12,n45,n14,n25;
3736 if(i0>0) { //reversed case
3748 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3749 prevNod[n4], prevNod[n5], nextNod[n5],
3750 prevNod[n12], midlNod[n2], nextNod[n12],
3751 prevNod[n45], midlNod[n5], nextNod[n45],
3752 prevNod[n14], prevNod[n25], nextNod[n25]);
3757 // realized for extrusion only
3758 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3759 //vector<int> quantities (nbNodes + 2);
3761 //quantities[0] = nbNodes; // bottom of prism
3762 //for (int inode = 0; inode < nbNodes; inode++) {
3763 // polyedre_nodes[inode] = prevNod[inode];
3766 //quantities[1] = nbNodes; // top of prism
3767 //for (int inode = 0; inode < nbNodes; inode++) {
3768 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3771 //for (int iface = 0; iface < nbNodes; iface++) {
3772 // quantities[iface + 2] = 4;
3773 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3774 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3775 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3776 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3777 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3779 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3786 // realized for extrusion only
3787 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3788 vector<int> quantities (nbNodes + 2);
3790 quantities[0] = nbNodes; // bottom of prism
3791 for (int inode = 0; inode < nbNodes; inode++) {
3792 polyedre_nodes[inode] = prevNod[inode];
3795 quantities[1] = nbNodes; // top of prism
3796 for (int inode = 0; inode < nbNodes; inode++) {
3797 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3800 for (int iface = 0; iface < nbNodes; iface++) {
3801 quantities[iface + 2] = 4;
3802 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3803 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3804 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3805 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3806 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3808 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3812 newElems.push_back( aNewElem );
3813 myLastCreatedElems.Append(aNewElem);
3814 srcElements.Append( elem );
3815 lastElem = aNewElem;
3818 // set new prev nodes
3819 for ( iNode = 0; iNode < nbNodes; iNode++ )
3820 prevNod[ iNode ] = nextNod[ iNode ];
3825 //=======================================================================
3827 * \brief Create 1D and 2D elements around swept elements
3828 * \param mapNewNodes - source nodes and ones generated from them
3829 * \param newElemsMap - source elements and ones generated from them
3830 * \param elemNewNodesMap - nodes generated from each node of each element
3831 * \param elemSet - all swept elements
3832 * \param nbSteps - number of sweeping steps
3833 * \param srcElements - to append elem for each generated element
3835 //=======================================================================
3837 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3838 TElemOfElemListMap & newElemsMap,
3839 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3840 TIDSortedElemSet& elemSet,
3842 SMESH_SequenceOfElemPtr& srcElements)
3844 MESSAGE("makeWalls");
3845 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3846 SMESHDS_Mesh* aMesh = GetMeshDS();
3848 // Find nodes belonging to only one initial element - sweep them to get edges.
3850 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3851 for ( ; nList != mapNewNodes.end(); nList++ ) {
3852 const SMDS_MeshNode* node =
3853 static_cast<const SMDS_MeshNode*>( nList->first );
3854 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3855 int nbInitElems = 0;
3856 const SMDS_MeshElement* el = 0;
3857 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3858 while ( eIt->more() && nbInitElems < 2 ) {
3860 SMDSAbs_ElementType type = el->GetType();
3861 if ( type == SMDSAbs_Volume || type < highType ) continue;
3862 if ( type > highType ) {
3866 if ( elemSet.find(el) != elemSet.end() )
3869 if ( nbInitElems < 2 ) {
3870 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3871 if(!NotCreateEdge) {
3872 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3873 list<const SMDS_MeshElement*> newEdges;
3874 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3879 // Make a ceiling for each element ie an equal element of last new nodes.
3880 // Find free links of faces - make edges and sweep them into faces.
3882 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3883 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3884 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3885 const SMDS_MeshElement* elem = itElem->first;
3886 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3888 if(itElem->second.size()==0) continue;
3890 if ( elem->GetType() == SMDSAbs_Edge ) {
3891 // create a ceiling edge
3892 if (!elem->IsQuadratic()) {
3893 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3894 vecNewNodes[ 1 ]->second.back())) {
3895 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3896 vecNewNodes[ 1 ]->second.back()));
3897 srcElements.Append( myLastCreatedElems.Last() );
3901 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3902 vecNewNodes[ 1 ]->second.back(),
3903 vecNewNodes[ 2 ]->second.back())) {
3904 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3905 vecNewNodes[ 1 ]->second.back(),
3906 vecNewNodes[ 2 ]->second.back()));
3907 srcElements.Append( myLastCreatedElems.Last() );
3911 if ( elem->GetType() != SMDSAbs_Face )
3914 bool hasFreeLinks = false;
3916 TIDSortedElemSet avoidSet;
3917 avoidSet.insert( elem );
3919 set<const SMDS_MeshNode*> aFaceLastNodes;
3920 int iNode, nbNodes = vecNewNodes.size();
3921 if(!elem->IsQuadratic()) {
3922 // loop on the face nodes
3923 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3924 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3925 // look for free links of the face
3926 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3927 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3928 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3929 // check if a link is free
3930 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3931 hasFreeLinks = true;
3932 // make an edge and a ceiling for a new edge
3933 if ( !aMesh->FindEdge( n1, n2 )) {
3934 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3935 srcElements.Append( myLastCreatedElems.Last() );
3937 n1 = vecNewNodes[ iNode ]->second.back();
3938 n2 = vecNewNodes[ iNext ]->second.back();
3939 if ( !aMesh->FindEdge( n1, n2 )) {
3940 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3941 srcElements.Append( myLastCreatedElems.Last() );
3946 else { // elem is quadratic face
3947 int nbn = nbNodes/2;
3948 for ( iNode = 0; iNode < nbn; iNode++ ) {
3949 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3950 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3951 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3952 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3953 // check if a link is free
3954 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3955 hasFreeLinks = true;
3956 // make an edge and a ceiling for a new edge
3958 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3959 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3960 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3961 srcElements.Append( myLastCreatedElems.Last() );
3963 n1 = vecNewNodes[ iNode ]->second.back();
3964 n2 = vecNewNodes[ iNext ]->second.back();
3965 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3966 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3967 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3968 srcElements.Append( myLastCreatedElems.Last() );
3972 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3973 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3977 // sweep free links into faces
3979 if ( hasFreeLinks ) {
3980 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3981 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3983 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3984 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3985 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3986 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3988 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3989 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3991 while ( iVol++ < volNb ) v++;
3992 // find indices of free faces of a volume and their source edges
3993 list< int > freeInd;
3994 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3995 SMDS_VolumeTool vTool( *v );
3996 int iF, nbF = vTool.NbFaces();
3997 for ( iF = 0; iF < nbF; iF ++ ) {
3998 if (vTool.IsFreeFace( iF ) &&
3999 vTool.GetFaceNodes( iF, faceNodeSet ) &&
4000 initNodeSet != faceNodeSet) // except an initial face
4002 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4004 freeInd.push_back( iF );
4005 // find source edge of a free face iF
4006 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4007 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4008 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4009 initNodeSet.begin(), initNodeSet.end(),
4010 commonNodes.begin());
4011 if ( (*v)->IsQuadratic() )
4012 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4014 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4016 if ( !srcEdges.back() )
4018 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4019 << iF << " of volume #" << vTool.ID() << endl;
4024 if ( freeInd.empty() )
4027 // create faces for all steps;
4028 // if such a face has been already created by sweep of edge,
4029 // assure that its orientation is OK
4030 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4032 vTool.SetExternalNormal();
4033 list< int >::iterator ind = freeInd.begin();
4034 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4035 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4037 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4038 int nbn = vTool.NbFaceNodes( *ind );
4040 case 3: { ///// triangle
4041 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4043 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4044 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4046 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4047 aMesh->RemoveElement(f);
4051 case 4: { ///// quadrangle
4052 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4054 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4055 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4057 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4058 aMesh->RemoveElement(f);
4063 if( (*v)->IsQuadratic() ) {
4064 if(nbn==6) { /////// quadratic triangle
4065 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4066 nodes[1], nodes[3], nodes[5] );
4068 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069 nodes[1], nodes[3], nodes[5]));
4071 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4072 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4073 tmpnodes[0] = nodes[0];
4074 tmpnodes[1] = nodes[2];
4075 tmpnodes[2] = nodes[4];
4076 tmpnodes[3] = nodes[1];
4077 tmpnodes[4] = nodes[3];
4078 tmpnodes[5] = nodes[5];
4079 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4080 nodes[1], nodes[3], nodes[5]));
4081 aMesh->RemoveElement(f);
4084 else { /////// quadratic quadrangle
4085 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4086 nodes[1], nodes[3], nodes[5], nodes[7] );
4088 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4089 nodes[1], nodes[3], nodes[5], nodes[7]));
4091 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4092 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4093 tmpnodes[0] = nodes[0];
4094 tmpnodes[1] = nodes[2];
4095 tmpnodes[2] = nodes[4];
4096 tmpnodes[3] = nodes[6];
4097 tmpnodes[4] = nodes[1];
4098 tmpnodes[5] = nodes[3];
4099 tmpnodes[6] = nodes[5];
4100 tmpnodes[7] = nodes[7];
4101 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4102 nodes[1], nodes[3], nodes[5], nodes[7]));
4103 aMesh->RemoveElement(f);
4107 else { //////// polygon
4108 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4109 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4111 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4112 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4114 // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4115 MESSAGE("ChangeElementNodes");
4116 aMesh->ChangeElementNodes( f, nodes, nbn );
4120 while ( srcElements.Length() < myLastCreatedElems.Length() )
4121 srcElements.Append( *srcEdge );
4123 } // loop on free faces
4125 // go to the next volume
4127 while ( iVol++ < nbVolumesByStep ) v++;
4130 } // sweep free links into faces
4132 // Make a ceiling face with a normal external to a volume
4134 SMDS_VolumeTool lastVol( itElem->second.back() );
4136 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4138 lastVol.SetExternalNormal();
4139 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4140 int nbn = lastVol.NbFaceNodes( iF );
4143 if (!hasFreeLinks ||
4144 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4145 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4148 if (!hasFreeLinks ||
4149 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4150 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4153 if(itElem->second.back()->IsQuadratic()) {
4155 if (!hasFreeLinks ||
4156 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4157 nodes[1], nodes[3], nodes[5]) ) {
4158 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4159 nodes[1], nodes[3], nodes[5]));
4163 if (!hasFreeLinks ||
4164 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4165 nodes[1], nodes[3], nodes[5], nodes[7]) )
4166 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4167 nodes[1], nodes[3], nodes[5], nodes[7]));
4171 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4172 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4173 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4177 while ( srcElements.Length() < myLastCreatedElems.Length() )
4178 srcElements.Append( myLastCreatedElems.Last() );
4180 } // loop on swept elements
4183 //=======================================================================
4184 //function : RotationSweep
4186 //=======================================================================
4188 SMESH_MeshEditor::PGroupIDs
4189 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4190 const gp_Ax1& theAxis,
4191 const double theAngle,
4192 const int theNbSteps,
4193 const double theTol,
4194 const bool theMakeGroups,
4195 const bool theMakeWalls)
4197 myLastCreatedElems.Clear();
4198 myLastCreatedNodes.Clear();
4200 // source elements for each generated one
4201 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4203 MESSAGE( "RotationSweep()");
4205 aTrsf.SetRotation( theAxis, theAngle );
4207 aTrsf2.SetRotation( theAxis, theAngle/2. );
4209 gp_Lin aLine( theAxis );
4210 double aSqTol = theTol * theTol;
4212 SMESHDS_Mesh* aMesh = GetMeshDS();
4214 TNodeOfNodeListMap mapNewNodes;
4215 TElemOfVecOfNnlmiMap mapElemNewNodes;
4216 TElemOfElemListMap newElemsMap;
4219 TIDSortedElemSet::iterator itElem;
4220 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4221 const SMDS_MeshElement* elem = *itElem;
4222 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4224 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4225 newNodesItVec.reserve( elem->NbNodes() );
4227 // loop on elem nodes
4228 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4229 while ( itN->more() ) {
4230 // check if a node has been already sweeped
4231 const SMDS_MeshNode* node = cast2Node( itN->next() );
4233 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4235 aXYZ.Coord( coord[0], coord[1], coord[2] );
4236 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4238 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4239 if ( nIt == mapNewNodes.end() ) {
4240 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4241 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4244 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4246 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4247 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4248 const SMDS_MeshNode * newNode = node;
4249 for ( int i = 0; i < theNbSteps; i++ ) {
4251 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4253 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4254 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4255 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4256 myLastCreatedNodes.Append(newNode);
4257 srcNodes.Append( node );
4258 listNewNodes.push_back( newNode );
4259 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4260 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4263 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4265 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4266 myLastCreatedNodes.Append(newNode);
4267 srcNodes.Append( node );
4268 listNewNodes.push_back( newNode );
4271 listNewNodes.push_back( newNode );
4272 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4273 listNewNodes.push_back( newNode );
4280 // if current elem is quadratic and current node is not medium
4281 // we have to check - may be it is needed to insert additional nodes
4282 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4283 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4284 if(listNewNodes.size()==theNbSteps) {
4285 listNewNodes.clear();
4287 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4289 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4290 const SMDS_MeshNode * newNode = node;
4292 for(int i = 0; i<theNbSteps; i++) {
4293 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4294 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4295 cout<<" 3 AddNode: "<<newNode;
4296 myLastCreatedNodes.Append(newNode);
4297 listNewNodes.push_back( newNode );
4298 srcNodes.Append( node );
4299 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4300 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4301 cout<<" 4 AddNode: "<<newNode;
4302 myLastCreatedNodes.Append(newNode);
4303 srcNodes.Append( node );
4304 listNewNodes.push_back( newNode );
4308 listNewNodes.push_back( newNode );
4314 newNodesItVec.push_back( nIt );
4316 // make new elements
4317 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4321 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4323 PGroupIDs newGroupIDs;
4324 if ( theMakeGroups )
4325 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4331 //=======================================================================
4332 //function : CreateNode
4334 //=======================================================================
4335 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4338 const double tolnode,
4339 SMESH_SequenceOfNode& aNodes)
4341 myLastCreatedElems.Clear();
4342 myLastCreatedNodes.Clear();
4345 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4347 // try to search in sequence of existing nodes
4348 // if aNodes.Length()>0 we 'nave to use given sequence
4349 // else - use all nodes of mesh
4350 if(aNodes.Length()>0) {
4352 for(i=1; i<=aNodes.Length(); i++) {
4353 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4354 if(P1.Distance(P2)<tolnode)
4355 return aNodes.Value(i);
4359 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4360 while(itn->more()) {
4361 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4362 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4363 if(P1.Distance(P2)<tolnode)
4368 // create new node and return it
4369 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4370 myLastCreatedNodes.Append(NewNode);
4375 //=======================================================================
4376 //function : ExtrusionSweep
4378 //=======================================================================
4380 SMESH_MeshEditor::PGroupIDs
4381 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4382 const gp_Vec& theStep,
4383 const int theNbSteps,
4384 TElemOfElemListMap& newElemsMap,
4385 const bool theMakeGroups,
4387 const double theTolerance)
4389 ExtrusParam aParams;
4390 aParams.myDir = gp_Dir(theStep);
4391 aParams.myNodes.Clear();
4392 aParams.mySteps = new TColStd_HSequenceOfReal;
4394 for(i=1; i<=theNbSteps; i++)
4395 aParams.mySteps->Append(theStep.Magnitude());
4398 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4402 //=======================================================================
4403 //function : ExtrusionSweep
4405 //=======================================================================
4407 SMESH_MeshEditor::PGroupIDs
4408 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4409 ExtrusParam& theParams,
4410 TElemOfElemListMap& newElemsMap,
4411 const bool theMakeGroups,
4413 const double theTolerance)
4415 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4416 myLastCreatedElems.Clear();
4417 myLastCreatedNodes.Clear();
4419 // source elements for each generated one
4420 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4422 SMESHDS_Mesh* aMesh = GetMeshDS();
4424 int nbsteps = theParams.mySteps->Length();
4426 TNodeOfNodeListMap mapNewNodes;
4427 //TNodeOfNodeVecMap mapNewNodes;
4428 TElemOfVecOfNnlmiMap mapElemNewNodes;
4429 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4432 TIDSortedElemSet::iterator itElem;
4433 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4434 // check element type
4435 const SMDS_MeshElement* elem = *itElem;
4436 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4439 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4440 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4441 newNodesItVec.reserve( elem->NbNodes() );
4443 // loop on elem nodes
4444 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4445 while ( itN->more() )
4447 // check if a node has been already sweeped
4448 const SMDS_MeshNode* node = cast2Node( itN->next() );
4449 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4450 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4451 if ( nIt == mapNewNodes.end() ) {
4452 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4453 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4454 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4455 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4456 //vecNewNodes.reserve(nbsteps);
4459 double coord[] = { node->X(), node->Y(), node->Z() };
4460 //int nbsteps = theParams.mySteps->Length();
4461 for ( int i = 0; i < nbsteps; i++ ) {
4462 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4463 // create additional node
4464 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4465 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4466 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4467 if( theFlags & EXTRUSION_FLAG_SEW ) {
4468 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4469 theTolerance, theParams.myNodes);
4470 listNewNodes.push_back( newNode );
4473 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4474 myLastCreatedNodes.Append(newNode);
4475 srcNodes.Append( node );
4476 listNewNodes.push_back( newNode );
4479 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4480 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4481 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4482 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4483 if( theFlags & EXTRUSION_FLAG_SEW ) {
4484 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4485 theTolerance, theParams.myNodes);
4486 listNewNodes.push_back( newNode );
4487 //vecNewNodes[i]=newNode;
4490 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4491 myLastCreatedNodes.Append(newNode);
4492 srcNodes.Append( node );
4493 listNewNodes.push_back( newNode );
4494 //vecNewNodes[i]=newNode;
4499 // if current elem is quadratic and current node is not medium
4500 // we have to check - may be it is needed to insert additional nodes
4501 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4502 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4503 if(listNewNodes.size()==nbsteps) {
4504 listNewNodes.clear();
4505 double coord[] = { node->X(), node->Y(), node->Z() };
4506 for ( int i = 0; i < nbsteps; i++ ) {
4507 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4508 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4509 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4510 if( theFlags & EXTRUSION_FLAG_SEW ) {
4511 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4512 theTolerance, theParams.myNodes);
4513 listNewNodes.push_back( newNode );
4516 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4517 myLastCreatedNodes.Append(newNode);
4518 srcNodes.Append( node );
4519 listNewNodes.push_back( newNode );
4521 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4522 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4523 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4524 if( theFlags & EXTRUSION_FLAG_SEW ) {
4525 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4526 theTolerance, theParams.myNodes);
4527 listNewNodes.push_back( newNode );
4530 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4531 myLastCreatedNodes.Append(newNode);
4532 srcNodes.Append( node );
4533 listNewNodes.push_back( newNode );
4539 newNodesItVec.push_back( nIt );
4541 // make new elements
4542 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4545 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4546 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4548 PGroupIDs newGroupIDs;
4549 if ( theMakeGroups )
4550 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4556 //=======================================================================
4557 //class : SMESH_MeshEditor_PathPoint
4558 //purpose : auxiliary class
4559 //=======================================================================
4560 class SMESH_MeshEditor_PathPoint {
4562 SMESH_MeshEditor_PathPoint() {
4563 myPnt.SetCoord(99., 99., 99.);
4564 myTgt.SetCoord(1.,0.,0.);
4568 void SetPnt(const gp_Pnt& aP3D){
4571 void SetTangent(const gp_Dir& aTgt){
4574 void SetAngle(const double& aBeta){
4577 void SetParameter(const double& aPrm){
4580 const gp_Pnt& Pnt()const{
4583 const gp_Dir& Tangent()const{
4586 double Angle()const{
4589 double Parameter()const{
4601 //=======================================================================
4602 //function : ExtrusionAlongTrack
4604 //=======================================================================
4605 SMESH_MeshEditor::Extrusion_Error
4606 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4607 SMESH_subMesh* theTrack,
4608 const SMDS_MeshNode* theN1,
4609 const bool theHasAngles,
4610 list<double>& theAngles,
4611 const bool theLinearVariation,
4612 const bool theHasRefPoint,
4613 const gp_Pnt& theRefPoint,
4614 const bool theMakeGroups)
4616 MESSAGE("ExtrusionAlongTrack");
4617 myLastCreatedElems.Clear();
4618 myLastCreatedNodes.Clear();
4621 std::list<double> aPrms;
4622 TIDSortedElemSet::iterator itElem;
4625 TopoDS_Edge aTrackEdge;
4626 TopoDS_Vertex aV1, aV2;
4628 SMDS_ElemIteratorPtr aItE;
4629 SMDS_NodeIteratorPtr aItN;
4630 SMDSAbs_ElementType aTypeE;
4632 TNodeOfNodeListMap mapNewNodes;
4635 aNbE = theElements.size();
4638 return EXTR_NO_ELEMENTS;
4640 // 1.1 Track Pattern
4643 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4645 aItE = pSubMeshDS->GetElements();
4646 while ( aItE->more() ) {
4647 const SMDS_MeshElement* pE = aItE->next();
4648 aTypeE = pE->GetType();
4649 // Pattern must contain links only
4650 if ( aTypeE != SMDSAbs_Edge )
4651 return EXTR_PATH_NOT_EDGE;
4654 list<SMESH_MeshEditor_PathPoint> fullList;
4656 const TopoDS_Shape& aS = theTrack->GetSubShape();
4657 // Sub shape for the Pattern must be an Edge or Wire
4658 if( aS.ShapeType() == TopAbs_EDGE ) {
4659 aTrackEdge = TopoDS::Edge( aS );
4660 // the Edge must not be degenerated
4661 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4662 return EXTR_BAD_PATH_SHAPE;
4663 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4664 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4665 const SMDS_MeshNode* aN1 = aItN->next();
4666 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4667 const SMDS_MeshNode* aN2 = aItN->next();
4668 // starting node must be aN1 or aN2
4669 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4670 return EXTR_BAD_STARTING_NODE;
4671 aItN = pSubMeshDS->GetNodes();
4672 while ( aItN->more() ) {
4673 const SMDS_MeshNode* pNode = aItN->next();
4674 const SMDS_EdgePosition* pEPos =
4675 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4676 double aT = pEPos->GetUParameter();
4677 aPrms.push_back( aT );
4679 //Extrusion_Error err =
4680 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4682 else if( aS.ShapeType() == TopAbs_WIRE ) {
4683 list< SMESH_subMesh* > LSM;
4684 TopTools_SequenceOfShape Edges;
4685 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4686 while(itSM->more()) {
4687 SMESH_subMesh* SM = itSM->next();
4689 const TopoDS_Shape& aS = SM->GetSubShape();
4692 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4693 int startNid = theN1->GetID();
4694 TColStd_MapOfInteger UsedNums;
4695 int NbEdges = Edges.Length();
4697 for(; i<=NbEdges; i++) {
4699 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4700 for(; itLSM!=LSM.end(); itLSM++) {
4702 if(UsedNums.Contains(k)) continue;
4703 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4704 SMESH_subMesh* locTrack = *itLSM;
4705 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4706 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4707 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4708 const SMDS_MeshNode* aN1 = aItN->next();
4709 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4710 const SMDS_MeshNode* aN2 = aItN->next();
4711 // starting node must be aN1 or aN2
4712 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4713 // 2. Collect parameters on the track edge
4715 aItN = locMeshDS->GetNodes();
4716 while ( aItN->more() ) {
4717 const SMDS_MeshNode* pNode = aItN->next();
4718 const SMDS_EdgePosition* pEPos =
4719 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4720 double aT = pEPos->GetUParameter();
4721 aPrms.push_back( aT );
4723 list<SMESH_MeshEditor_PathPoint> LPP;
4724 //Extrusion_Error err =
4725 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4726 LLPPs.push_back(LPP);
4728 // update startN for search following egde
4729 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4730 else startNid = aN1->GetID();
4734 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4735 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4736 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4737 for(; itPP!=firstList.end(); itPP++) {
4738 fullList.push_back( *itPP );
4740 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4741 fullList.pop_back();
4743 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4744 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4745 itPP = currList.begin();
4746 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4747 gp_Dir D1 = PP1.Tangent();
4748 gp_Dir D2 = PP2.Tangent();
4749 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4750 (D1.Z()+D2.Z())/2 ) );
4751 PP1.SetTangent(Dnew);
4752 fullList.push_back(PP1);
4754 for(; itPP!=firstList.end(); itPP++) {
4755 fullList.push_back( *itPP );
4757 PP1 = fullList.back();
4758 fullList.pop_back();
4760 // if wire not closed
4761 fullList.push_back(PP1);
4765 return EXTR_BAD_PATH_SHAPE;
4768 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4769 theHasRefPoint, theRefPoint, theMakeGroups);
4773 //=======================================================================
4774 //function : ExtrusionAlongTrack
4776 //=======================================================================
4777 SMESH_MeshEditor::Extrusion_Error
4778 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4779 SMESH_Mesh* theTrack,
4780 const SMDS_MeshNode* theN1,
4781 const bool theHasAngles,
4782 list<double>& theAngles,
4783 const bool theLinearVariation,
4784 const bool theHasRefPoint,
4785 const gp_Pnt& theRefPoint,
4786 const bool theMakeGroups)
4788 myLastCreatedElems.Clear();
4789 myLastCreatedNodes.Clear();
4792 std::list<double> aPrms;
4793 TIDSortedElemSet::iterator itElem;
4796 TopoDS_Edge aTrackEdge;
4797 TopoDS_Vertex aV1, aV2;
4799 SMDS_ElemIteratorPtr aItE;
4800 SMDS_NodeIteratorPtr aItN;
4801 SMDSAbs_ElementType aTypeE;
4803 TNodeOfNodeListMap mapNewNodes;
4806 aNbE = theElements.size();
4809 return EXTR_NO_ELEMENTS;
4811 // 1.1 Track Pattern
4814 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4816 aItE = pMeshDS->elementsIterator();
4817 while ( aItE->more() ) {
4818 const SMDS_MeshElement* pE = aItE->next();
4819 aTypeE = pE->GetType();
4820 // Pattern must contain links only
4821 if ( aTypeE != SMDSAbs_Edge )
4822 return EXTR_PATH_NOT_EDGE;
4825 list<SMESH_MeshEditor_PathPoint> fullList;
4827 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4828 // Sub shape for the Pattern must be an Edge or Wire
4829 if( aS.ShapeType() == TopAbs_EDGE ) {
4830 aTrackEdge = TopoDS::Edge( aS );
4831 // the Edge must not be degenerated
4832 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4833 return EXTR_BAD_PATH_SHAPE;
4834 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4835 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4836 const SMDS_MeshNode* aN1 = aItN->next();
4837 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4838 const SMDS_MeshNode* aN2 = aItN->next();
4839 // starting node must be aN1 or aN2
4840 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4841 return EXTR_BAD_STARTING_NODE;
4842 aItN = pMeshDS->nodesIterator();
4843 while ( aItN->more() ) {
4844 const SMDS_MeshNode* pNode = aItN->next();
4845 if( pNode==aN1 || pNode==aN2 ) continue;
4846 const SMDS_EdgePosition* pEPos =
4847 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4848 double aT = pEPos->GetUParameter();
4849 aPrms.push_back( aT );
4851 //Extrusion_Error err =
4852 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4854 else if( aS.ShapeType() == TopAbs_WIRE ) {
4855 list< SMESH_subMesh* > LSM;
4856 TopTools_SequenceOfShape Edges;
4857 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4858 for(; eExp.More(); eExp.Next()) {
4859 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4860 if( BRep_Tool::Degenerated(E) ) continue;
4861 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4867 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4868 int startNid = theN1->GetID();
4869 TColStd_MapOfInteger UsedNums;
4870 int NbEdges = Edges.Length();
4872 for(; i<=NbEdges; i++) {
4874 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4875 for(; itLSM!=LSM.end(); itLSM++) {
4877 if(UsedNums.Contains(k)) continue;
4878 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4879 SMESH_subMesh* locTrack = *itLSM;
4880 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4881 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4882 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4883 const SMDS_MeshNode* aN1 = aItN->next();
4884 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4885 const SMDS_MeshNode* aN2 = aItN->next();
4886 // starting node must be aN1 or aN2
4887 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4888 // 2. Collect parameters on the track edge
4890 aItN = locMeshDS->GetNodes();
4891 while ( aItN->more() ) {
4892 const SMDS_MeshNode* pNode = aItN->next();
4893 const SMDS_EdgePosition* pEPos =
4894 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4895 double aT = pEPos->GetUParameter();
4896 aPrms.push_back( aT );
4898 list<SMESH_MeshEditor_PathPoint> LPP;
4899 //Extrusion_Error err =
4900 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4901 LLPPs.push_back(LPP);
4903 // update startN for search following egde
4904 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4905 else startNid = aN1->GetID();
4909 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4910 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4911 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4912 for(; itPP!=firstList.end(); itPP++) {
4913 fullList.push_back( *itPP );
4915 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4916 fullList.pop_back();
4918 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4919 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4920 itPP = currList.begin();
4921 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4922 gp_Pnt P1 = PP1.Pnt();
4923 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4924 gp_Pnt P2 = PP2.Pnt();
4925 gp_Dir D1 = PP1.Tangent();
4926 gp_Dir D2 = PP2.Tangent();
4927 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4928 (D1.Z()+D2.Z())/2 ) );
4929 PP1.SetTangent(Dnew);
4930 fullList.push_back(PP1);
4932 for(; itPP!=currList.end(); itPP++) {
4933 fullList.push_back( *itPP );
4935 PP1 = fullList.back();
4936 fullList.pop_back();
4938 // if wire not closed
4939 fullList.push_back(PP1);
4943 return EXTR_BAD_PATH_SHAPE;
4946 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4947 theHasRefPoint, theRefPoint, theMakeGroups);
4951 //=======================================================================
4952 //function : MakeEdgePathPoints
4953 //purpose : auxilary for ExtrusionAlongTrack
4954 //=======================================================================
4955 SMESH_MeshEditor::Extrusion_Error
4956 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4957 const TopoDS_Edge& aTrackEdge,
4959 list<SMESH_MeshEditor_PathPoint>& LPP)
4961 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4963 aTolVec2=aTolVec*aTolVec;
4965 TopoDS_Vertex aV1, aV2;
4966 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4967 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4968 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4969 // 2. Collect parameters on the track edge
4970 aPrms.push_front( aT1 );
4971 aPrms.push_back( aT2 );
4974 if( FirstIsStart ) {
4985 SMESH_MeshEditor_PathPoint aPP;
4986 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4987 std::list<double>::iterator aItD = aPrms.begin();
4988 for(; aItD != aPrms.end(); ++aItD) {
4992 aC3D->D1( aT, aP3D, aVec );
4993 aL2 = aVec.SquareMagnitude();
4994 if ( aL2 < aTolVec2 )
4995 return EXTR_CANT_GET_TANGENT;
4996 gp_Dir aTgt( aVec );
4998 aPP.SetTangent( aTgt );
4999 aPP.SetParameter( aT );
5006 //=======================================================================
5007 //function : MakeExtrElements
5008 //purpose : auxilary for ExtrusionAlongTrack
5009 //=======================================================================
5010 SMESH_MeshEditor::Extrusion_Error
5011 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5012 list<SMESH_MeshEditor_PathPoint>& fullList,
5013 const bool theHasAngles,
5014 list<double>& theAngles,
5015 const bool theLinearVariation,
5016 const bool theHasRefPoint,
5017 const gp_Pnt& theRefPoint,
5018 const bool theMakeGroups)
5020 MESSAGE("MakeExtrElements");
5021 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5022 int aNbTP = fullList.size();
5023 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5025 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5026 LinearAngleVariation(aNbTP-1, theAngles);
5028 vector<double> aAngles( aNbTP );
5030 for(; j<aNbTP; ++j) {
5033 if ( theHasAngles ) {
5035 std::list<double>::iterator aItD = theAngles.begin();
5036 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5038 aAngles[j] = anAngle;
5041 // fill vector of path points with angles
5042 //aPPs.resize(fullList.size());
5044 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5045 for(; itPP!=fullList.end(); itPP++) {
5047 SMESH_MeshEditor_PathPoint PP = *itPP;
5048 PP.SetAngle(aAngles[j]);
5052 TNodeOfNodeListMap mapNewNodes;
5053 TElemOfVecOfNnlmiMap mapElemNewNodes;
5054 TElemOfElemListMap newElemsMap;
5055 TIDSortedElemSet::iterator itElem;
5058 SMDSAbs_ElementType aTypeE;
5059 // source elements for each generated one
5060 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5062 // 3. Center of rotation aV0
5063 gp_Pnt aV0 = theRefPoint;
5065 if ( !theHasRefPoint ) {
5067 aGC.SetCoord( 0.,0.,0. );
5069 itElem = theElements.begin();
5070 for ( ; itElem != theElements.end(); itElem++ ) {
5071 const SMDS_MeshElement* elem = *itElem;
5073 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5074 while ( itN->more() ) {
5075 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5080 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5081 list<const SMDS_MeshNode*> aLNx;
5082 mapNewNodes[node] = aLNx;
5084 gp_XYZ aXYZ( aX, aY, aZ );
5092 } // if (!theHasRefPoint) {
5093 mapNewNodes.clear();
5095 // 4. Processing the elements
5096 SMESHDS_Mesh* aMesh = GetMeshDS();
5098 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5099 // check element type
5100 const SMDS_MeshElement* elem = *itElem;
5101 aTypeE = elem->GetType();
5102 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5105 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5106 newNodesItVec.reserve( elem->NbNodes() );
5108 // loop on elem nodes
5110 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5111 while ( itN->more() )
5114 // check if a node has been already processed
5115 const SMDS_MeshNode* node =
5116 static_cast<const SMDS_MeshNode*>( itN->next() );
5117 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5118 if ( nIt == mapNewNodes.end() ) {
5119 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5120 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5123 aX = node->X(); aY = node->Y(); aZ = node->Z();
5125 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5126 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5127 gp_Ax1 anAx1, anAxT1T0;
5128 gp_Dir aDT1x, aDT0x, aDT1T0;
5133 aPN0.SetCoord(aX, aY, aZ);
5135 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5137 aDT0x= aPP0.Tangent();
5138 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5140 for ( j = 1; j < aNbTP; ++j ) {
5141 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5143 aDT1x = aPP1.Tangent();
5144 aAngle1x = aPP1.Angle();
5146 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5148 gp_Vec aV01x( aP0x, aP1x );
5149 aTrsf.SetTranslation( aV01x );
5152 aV1x = aV0x.Transformed( aTrsf );
5153 aPN1 = aPN0.Transformed( aTrsf );
5155 // rotation 1 [ T1,T0 ]
5156 aAngleT1T0=-aDT1x.Angle( aDT0x );
5157 if (fabs(aAngleT1T0) > aTolAng) {
5159 anAxT1T0.SetLocation( aV1x );
5160 anAxT1T0.SetDirection( aDT1T0 );
5161 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5163 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5167 if ( theHasAngles ) {
5168 anAx1.SetLocation( aV1x );
5169 anAx1.SetDirection( aDT1x );
5170 aTrsfRot.SetRotation( anAx1, aAngle1x );
5172 aPN1 = aPN1.Transformed( aTrsfRot );
5176 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5177 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5178 // create additional node
5179 double x = ( aPN1.X() + aPN0.X() )/2.;
5180 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5181 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5182 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5183 myLastCreatedNodes.Append(newNode);
5184 srcNodes.Append( node );
5185 listNewNodes.push_back( newNode );
5190 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5191 myLastCreatedNodes.Append(newNode);
5192 srcNodes.Append( node );
5193 listNewNodes.push_back( newNode );
5203 // if current elem is quadratic and current node is not medium
5204 // we have to check - may be it is needed to insert additional nodes
5205 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5206 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5207 if(listNewNodes.size()==aNbTP-1) {
5208 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5209 gp_XYZ P(node->X(), node->Y(), node->Z());
5210 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5212 for(i=0; i<aNbTP-1; i++) {
5213 const SMDS_MeshNode* N = *it;
5214 double x = ( N->X() + P.X() )/2.;
5215 double y = ( N->Y() + P.Y() )/2.;
5216 double z = ( N->Z() + P.Z() )/2.;
5217 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5218 srcNodes.Append( node );
5219 myLastCreatedNodes.Append(newN);
5222 P = gp_XYZ(N->X(),N->Y(),N->Z());
5224 listNewNodes.clear();
5225 for(i=0; i<2*(aNbTP-1); i++) {
5226 listNewNodes.push_back(aNodes[i]);
5232 newNodesItVec.push_back( nIt );
5234 // make new elements
5235 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5236 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5237 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5240 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5242 if ( theMakeGroups )
5243 generateGroups( srcNodes, srcElems, "extruded");
5249 //=======================================================================
5250 //function : LinearAngleVariation
5251 //purpose : auxilary for ExtrusionAlongTrack
5252 //=======================================================================
5253 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5254 list<double>& Angles)
5256 int nbAngles = Angles.size();
5257 if( nbSteps > nbAngles ) {
5258 vector<double> theAngles(nbAngles);
5259 list<double>::iterator it = Angles.begin();
5261 for(; it!=Angles.end(); it++) {
5263 theAngles[i] = (*it);
5266 double rAn2St = double( nbAngles ) / double( nbSteps );
5267 double angPrev = 0, angle;
5268 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5269 double angCur = rAn2St * ( iSt+1 );
5270 double angCurFloor = floor( angCur );
5271 double angPrevFloor = floor( angPrev );
5272 if ( angPrevFloor == angCurFloor )
5273 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5275 int iP = int( angPrevFloor );
5276 double angPrevCeil = ceil(angPrev);
5277 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5279 int iC = int( angCurFloor );
5280 if ( iC < nbAngles )
5281 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5283 iP = int( angPrevCeil );
5285 angle += theAngles[ iC ];
5287 res.push_back(angle);
5292 for(; it!=res.end(); it++)
5293 Angles.push_back( *it );
5298 //================================================================================
5300 * \brief Move or copy theElements applying theTrsf to their nodes
5301 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5302 * \param theTrsf - transformation to apply
5303 * \param theCopy - if true, create translated copies of theElems
5304 * \param theMakeGroups - if true and theCopy, create translated groups
5305 * \param theTargetMesh - mesh to copy translated elements into
5306 * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5308 //================================================================================
5310 SMESH_MeshEditor::PGroupIDs
5311 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5312 const gp_Trsf& theTrsf,
5314 const bool theMakeGroups,
5315 SMESH_Mesh* theTargetMesh)
5317 myLastCreatedElems.Clear();
5318 myLastCreatedNodes.Clear();
5320 bool needReverse = false;
5321 string groupPostfix;
5322 switch ( theTrsf.Form() ) {
5324 MESSAGE("gp_PntMirror");
5326 groupPostfix = "mirrored";
5329 MESSAGE("gp_Ax1Mirror");
5330 groupPostfix = "mirrored";
5333 MESSAGE("gp_Ax2Mirror");
5335 groupPostfix = "mirrored";
5338 MESSAGE("gp_Rotation");
5339 groupPostfix = "rotated";
5341 case gp_Translation:
5342 MESSAGE("gp_Translation");
5343 groupPostfix = "translated";
5346 MESSAGE("gp_Scale");
5347 groupPostfix = "scaled";
5349 case gp_CompoundTrsf: // different scale by axis
5350 MESSAGE("gp_CompoundTrsf");
5351 groupPostfix = "scaled";
5355 needReverse = false;
5356 groupPostfix = "transformed";
5359 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5360 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5361 SMESHDS_Mesh* aMesh = GetMeshDS();
5364 // map old node to new one
5365 TNodeNodeMap nodeMap;
5367 // elements sharing moved nodes; those of them which have all
5368 // nodes mirrored but are not in theElems are to be reversed
5369 TIDSortedElemSet inverseElemSet;
5371 // source elements for each generated one
5372 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5374 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5375 TIDSortedElemSet orphanNode;
5377 if ( theElems.empty() ) // transform the whole mesh
5380 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5381 while ( eIt->more() ) theElems.insert( eIt->next() );
5383 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5384 while ( nIt->more() )
5386 const SMDS_MeshNode* node = nIt->next();
5387 if ( node->NbInverseElements() == 0)
5388 orphanNode.insert( node );
5392 // loop on elements to transform nodes : first orphan nodes then elems
5393 TIDSortedElemSet::iterator itElem;
5394 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5395 for (int i=0; i<2; i++)
5396 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5397 const SMDS_MeshElement* elem = *itElem;
5401 // loop on elem nodes
5402 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5403 while ( itN->more() ) {
5405 const SMDS_MeshNode* node = cast2Node( itN->next() );
5406 // check if a node has been already transformed
5407 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5408 nodeMap.insert( make_pair ( node, node ));
5409 if ( !n2n_isnew.second )
5413 coord[0] = node->X();
5414 coord[1] = node->Y();
5415 coord[2] = node->Z();
5416 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5417 if ( theTargetMesh ) {
5418 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5419 n2n_isnew.first->second = newNode;
5420 myLastCreatedNodes.Append(newNode);
5421 srcNodes.Append( node );
5423 else if ( theCopy ) {
5424 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5425 n2n_isnew.first->second = newNode;
5426 myLastCreatedNodes.Append(newNode);
5427 srcNodes.Append( node );
5430 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5431 // node position on shape becomes invalid
5432 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5433 ( SMDS_SpacePosition::originSpacePosition() );
5436 // keep inverse elements
5437 if ( !theCopy && !theTargetMesh && needReverse ) {
5438 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5439 while ( invElemIt->more() ) {
5440 const SMDS_MeshElement* iel = invElemIt->next();
5441 inverseElemSet.insert( iel );
5447 // either create new elements or reverse mirrored ones
5448 if ( !theCopy && !needReverse && !theTargetMesh )
5451 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5452 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5453 theElems.insert( *invElemIt );
5455 // replicate or reverse elements
5456 // TODO revoir ordre reverse vtk
5458 REV_TETRA = 0, // = nbNodes - 4
5459 REV_PYRAMID = 1, // = nbNodes - 4
5460 REV_PENTA = 2, // = nbNodes - 4
5462 REV_HEXA = 4, // = nbNodes - 4
5466 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5467 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5468 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5469 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5470 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5471 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5474 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5476 const SMDS_MeshElement* elem = *itElem;
5477 if ( !elem || elem->GetType() == SMDSAbs_Node )
5480 int nbNodes = elem->NbNodes();
5481 int elemType = elem->GetType();
5483 if (elem->IsPoly()) {
5484 // Polygon or Polyhedral Volume
5485 switch ( elemType ) {
5488 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5490 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5491 while (itN->more()) {
5492 const SMDS_MeshNode* node =
5493 static_cast<const SMDS_MeshNode*>(itN->next());
5494 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5495 if (nodeMapIt == nodeMap.end())
5496 break; // not all nodes transformed
5498 // reverse mirrored faces and volumes
5499 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5501 poly_nodes[iNode] = (*nodeMapIt).second;
5505 if ( iNode != nbNodes )
5506 continue; // not all nodes transformed
5508 if ( theTargetMesh ) {
5509 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5510 srcElems.Append( elem );
5512 else if ( theCopy ) {
5513 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5514 srcElems.Append( elem );
5517 aMesh->ChangePolygonNodes(elem, poly_nodes);
5521 case SMDSAbs_Volume:
5523 // ATTENTION: Reversing is not yet done!!!
5524 const SMDS_VtkVolume* aPolyedre =
5525 dynamic_cast<const SMDS_VtkVolume*>( elem );
5527 MESSAGE("Warning: bad volumic element");
5531 vector<const SMDS_MeshNode*> poly_nodes;
5532 vector<int> quantities;
5534 bool allTransformed = true;
5535 int nbFaces = aPolyedre->NbFaces();
5536 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5537 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5538 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5539 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5540 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5541 if (nodeMapIt == nodeMap.end()) {
5542 allTransformed = false; // not all nodes transformed
5544 poly_nodes.push_back((*nodeMapIt).second);
5547 quantities.push_back(nbFaceNodes);
5549 if ( !allTransformed )
5550 continue; // not all nodes transformed
5552 if ( theTargetMesh ) {
5553 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5554 srcElems.Append( elem );
5556 else if ( theCopy ) {
5557 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5558 srcElems.Append( elem );
5561 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5571 int* i = index[ FORWARD ];
5572 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5573 if ( elemType == SMDSAbs_Face )
5574 i = index[ REV_FACE ];
5576 i = index[ nbNodes - 4 ];
5578 if(elem->IsQuadratic()) {
5579 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5582 if(nbNodes==3) { // quadratic edge
5583 static int anIds[] = {1,0,2};
5586 else if(nbNodes==6) { // quadratic triangle
5587 static int anIds[] = {0,2,1,5,4,3};
5590 else if(nbNodes==8) { // quadratic quadrangle
5591 static int anIds[] = {0,3,2,1,7,6,5,4};
5594 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5595 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5598 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5599 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5602 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5603 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5606 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5607 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5613 // find transformed nodes
5614 vector<const SMDS_MeshNode*> nodes(nbNodes);
5616 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5617 while ( itN->more() ) {
5618 const SMDS_MeshNode* node =
5619 static_cast<const SMDS_MeshNode*>( itN->next() );
5620 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5621 if ( nodeMapIt == nodeMap.end() )
5622 break; // not all nodes transformed
5623 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5625 if ( iNode != nbNodes )
5626 continue; // not all nodes transformed
5628 if ( theTargetMesh ) {
5629 if ( SMDS_MeshElement* copy =
5630 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5631 myLastCreatedElems.Append( copy );
5632 srcElems.Append( elem );
5635 else if ( theCopy ) {
5636 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5637 srcElems.Append( elem );
5640 // reverse element as it was reversed by transformation
5642 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5646 PGroupIDs newGroupIDs;
5648 if ( theMakeGroups && theCopy ||
5649 theMakeGroups && theTargetMesh )
5650 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5656 ////=======================================================================
5657 ////function : Scale
5659 ////=======================================================================
5661 //SMESH_MeshEditor::PGroupIDs
5662 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5663 // const gp_Pnt& thePoint,
5664 // const std::list<double>& theScaleFact,
5665 // const bool theCopy,
5666 // const bool theMakeGroups,
5667 // SMESH_Mesh* theTargetMesh)
5669 // MESSAGE("Scale");
5670 // myLastCreatedElems.Clear();
5671 // myLastCreatedNodes.Clear();
5673 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5674 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5675 // SMESHDS_Mesh* aMesh = GetMeshDS();
5677 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5678 // std::list<double>::const_iterator itS = theScaleFact.begin();
5680 // if(theScaleFact.size()==1) {
5684 // if(theScaleFact.size()==2) {
5689 // if(theScaleFact.size()>2) {
5696 // // map old node to new one
5697 // TNodeNodeMap nodeMap;
5699 // // elements sharing moved nodes; those of them which have all
5700 // // nodes mirrored but are not in theElems are to be reversed
5701 // TIDSortedElemSet inverseElemSet;
5703 // // source elements for each generated one
5704 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5706 // // loop on theElems
5707 // TIDSortedElemSet::iterator itElem;
5708 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5709 // const SMDS_MeshElement* elem = *itElem;
5713 // // loop on elem nodes
5714 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5715 // while ( itN->more() ) {
5717 // // check if a node has been already transformed
5718 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5719 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5720 // nodeMap.insert( make_pair ( node, node ));
5721 // if ( !n2n_isnew.second )
5724 // //double coord[3];
5725 // //coord[0] = node->X();
5726 // //coord[1] = node->Y();
5727 // //coord[2] = node->Z();
5728 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5729 // double dx = (node->X() - thePoint.X()) * scaleX;
5730 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5731 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5732 // if ( theTargetMesh ) {
5733 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5734 // const SMDS_MeshNode * newNode =
5735 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5736 // n2n_isnew.first->second = newNode;
5737 // myLastCreatedNodes.Append(newNode);
5738 // srcNodes.Append( node );
5740 // else if ( theCopy ) {
5741 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5742 // const SMDS_MeshNode * newNode =
5743 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5744 // n2n_isnew.first->second = newNode;
5745 // myLastCreatedNodes.Append(newNode);
5746 // srcNodes.Append( node );
5749 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5750 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5751 // // node position on shape becomes invalid
5752 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5753 // ( SMDS_SpacePosition::originSpacePosition() );
5756 // // keep inverse elements
5757 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5758 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5759 // // while ( invElemIt->more() ) {
5760 // // const SMDS_MeshElement* iel = invElemIt->next();
5761 // // inverseElemSet.insert( iel );
5767 // // either create new elements or reverse mirrored ones
5768 // //if ( !theCopy && !needReverse && !theTargetMesh )
5769 // if ( !theCopy && !theTargetMesh )
5770 // return PGroupIDs();
5772 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5773 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5774 // theElems.insert( *invElemIt );
5776 // // replicate or reverse elements
5779 // REV_TETRA = 0, // = nbNodes - 4
5780 // REV_PYRAMID = 1, // = nbNodes - 4
5781 // REV_PENTA = 2, // = nbNodes - 4
5783 // REV_HEXA = 4, // = nbNodes - 4
5786 // int index[][8] = {
5787 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5788 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5789 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5790 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5791 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5792 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5795 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5797 // const SMDS_MeshElement* elem = *itElem;
5798 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5801 // int nbNodes = elem->NbNodes();
5802 // int elemType = elem->GetType();
5804 // if (elem->IsPoly()) {
5805 // // Polygon or Polyhedral Volume
5806 // switch ( elemType ) {
5807 // case SMDSAbs_Face:
5809 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5811 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5812 // while (itN->more()) {
5813 // const SMDS_MeshNode* node =
5814 // static_cast<const SMDS_MeshNode*>(itN->next());
5815 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5816 // if (nodeMapIt == nodeMap.end())
5817 // break; // not all nodes transformed
5818 // //if (needReverse) {
5819 // // // reverse mirrored faces and volumes
5820 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5822 // poly_nodes[iNode] = (*nodeMapIt).second;
5826 // if ( iNode != nbNodes )
5827 // continue; // not all nodes transformed
5829 // if ( theTargetMesh ) {
5830 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5831 // srcElems.Append( elem );
5833 // else if ( theCopy ) {
5834 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5835 // srcElems.Append( elem );
5838 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5842 // case SMDSAbs_Volume:
5844 // // ATTENTION: Reversing is not yet done!!!
5845 // const SMDS_VtkVolume* aPolyedre =
5846 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5847 // if (!aPolyedre) {
5848 // MESSAGE("Warning: bad volumic element");
5852 // vector<const SMDS_MeshNode*> poly_nodes;
5853 // vector<int> quantities;
5855 // bool allTransformed = true;
5856 // int nbFaces = aPolyedre->NbFaces();
5857 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5858 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5859 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5860 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5861 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5862 // if (nodeMapIt == nodeMap.end()) {
5863 // allTransformed = false; // not all nodes transformed
5865 // poly_nodes.push_back((*nodeMapIt).second);
5868 // quantities.push_back(nbFaceNodes);
5870 // if ( !allTransformed )
5871 // continue; // not all nodes transformed
5873 // if ( theTargetMesh ) {
5874 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5875 // srcElems.Append( elem );
5877 // else if ( theCopy ) {
5878 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5879 // srcElems.Append( elem );
5882 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5891 // // Regular elements
5892 // int* i = index[ FORWARD ];
5893 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5894 // // if ( elemType == SMDSAbs_Face )
5895 // // i = index[ REV_FACE ];
5897 // // i = index[ nbNodes - 4 ];
5899 // if(elem->IsQuadratic()) {
5900 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5902 // //if(needReverse) {
5903 // // if(nbNodes==3) { // quadratic edge
5904 // // static int anIds[] = {1,0,2};
5907 // // else if(nbNodes==6) { // quadratic triangle
5908 // // static int anIds[] = {0,2,1,5,4,3};
5911 // // else if(nbNodes==8) { // quadratic quadrangle
5912 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5915 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5916 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5919 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5920 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5923 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5924 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5927 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5928 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5934 // // find transformed nodes
5935 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5937 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5938 // while ( itN->more() ) {
5939 // const SMDS_MeshNode* node =
5940 // static_cast<const SMDS_MeshNode*>( itN->next() );
5941 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5942 // if ( nodeMapIt == nodeMap.end() )
5943 // break; // not all nodes transformed
5944 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5946 // if ( iNode != nbNodes )
5947 // continue; // not all nodes transformed
5949 // if ( theTargetMesh ) {
5950 // if ( SMDS_MeshElement* copy =
5951 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5952 // myLastCreatedElems.Append( copy );
5953 // srcElems.Append( elem );
5956 // else if ( theCopy ) {
5957 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5958 // myLastCreatedElems.Append( copy );
5959 // srcElems.Append( elem );
5963 // // reverse element as it was reversed by transformation
5964 // if ( nbNodes > 2 )
5965 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5969 // PGroupIDs newGroupIDs;
5971 // if ( theMakeGroups && theCopy ||
5972 // theMakeGroups && theTargetMesh ) {
5973 // string groupPostfix = "scaled";
5974 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5977 // return newGroupIDs;
5981 //=======================================================================
5983 * \brief Create groups of elements made during transformation
5984 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5985 * \param elemGens - elements making corresponding myLastCreatedElems
5986 * \param postfix - to append to names of new groups
5988 //=======================================================================
5990 SMESH_MeshEditor::PGroupIDs
5991 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5992 const SMESH_SequenceOfElemPtr& elemGens,
5993 const std::string& postfix,
5994 SMESH_Mesh* targetMesh)
5996 PGroupIDs newGroupIDs( new list<int> );
5997 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5999 // Sort existing groups by types and collect their names
6001 // to store an old group and a generated new one
6002 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6003 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6005 set< string > groupNames;
6007 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6008 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6009 while ( groupIt->more() ) {
6010 SMESH_Group * group = groupIt->next();
6011 if ( !group ) continue;
6012 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6013 if ( !groupDS || groupDS->IsEmpty() ) continue;
6014 groupNames.insert( group->GetName() );
6015 groupDS->SetStoreName( group->GetName() );
6016 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6021 // loop on nodes and elements
6022 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6024 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6025 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6026 if ( gens.Length() != elems.Length() )
6027 throw SALOME_Exception(LOCALIZED("invalid args"));
6029 // loop on created elements
6030 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6032 const SMDS_MeshElement* sourceElem = gens( iElem );
6033 if ( !sourceElem ) {
6034 MESSAGE("generateGroups(): NULL source element");
6037 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6038 if ( groupsOldNew.empty() ) {
6039 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6040 ++iElem; // skip all elements made by sourceElem
6043 // collect all elements made by sourceElem
6044 list< const SMDS_MeshElement* > resultElems;
6045 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6046 if ( resElem != sourceElem )
6047 resultElems.push_back( resElem );
6048 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6049 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6050 if ( resElem != sourceElem )
6051 resultElems.push_back( resElem );
6052 // do not generate element groups from node ones
6053 if ( sourceElem->GetType() == SMDSAbs_Node &&
6054 elems( iElem )->GetType() != SMDSAbs_Node )
6057 // add resultElems to groups made by ones the sourceElem belongs to
6058 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6059 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6061 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6062 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6064 SMDS_MeshGroup* & newGroup = gOldNew->second;
6065 if ( !newGroup )// create a new group
6068 string name = oldGroup->GetStoreName();
6069 if ( !targetMesh ) {
6073 while ( !groupNames.insert( name ).second ) // name exists
6079 TCollection_AsciiString nbStr(nb+1);
6080 name.resize( name.rfind('_')+1 );
6081 name += nbStr.ToCString();
6088 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6090 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6091 newGroup = & groupDS->SMDSGroup();
6092 newGroupIDs->push_back( id );
6095 // fill in a new group
6096 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6097 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6098 newGroup->Add( *resElemIt );
6101 } // loop on created elements
6102 }// loop on nodes and elements
6107 //================================================================================
6109 * \brief Return list of group of nodes close to each other within theTolerance
6110 * Search among theNodes or in the whole mesh if theNodes is empty using
6111 * an Octree algorithm
6113 //================================================================================
6115 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6116 const double theTolerance,
6117 TListOfListOfNodes & theGroupsOfNodes)
6119 myLastCreatedElems.Clear();
6120 myLastCreatedNodes.Clear();
6122 if ( theNodes.empty() )
6123 { // get all nodes in the mesh
6124 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6125 while ( nIt->more() )
6126 theNodes.insert( theNodes.end(),nIt->next());
6129 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6133 //=======================================================================
6135 * \brief Implementation of search for the node closest to point
6137 //=======================================================================
6139 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6141 //---------------------------------------------------------------------
6143 * \brief Constructor
6145 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6147 myMesh = ( SMESHDS_Mesh* ) theMesh;
6149 TIDSortedNodeSet nodes;
6151 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6152 while ( nIt->more() )
6153 nodes.insert( nodes.end(), nIt->next() );
6155 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6157 // get max size of a leaf box
6158 SMESH_OctreeNode* tree = myOctreeNode;
6159 while ( !tree->isLeaf() )
6161 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6165 myHalfLeafSize = tree->maxSize() / 2.;
6168 //---------------------------------------------------------------------
6170 * \brief Move node and update myOctreeNode accordingly
6172 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6174 myOctreeNode->UpdateByMoveNode( node, toPnt );
6175 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6178 //---------------------------------------------------------------------
6180 * \brief Do it's job
6182 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6184 map<double, const SMDS_MeshNode*> dist2Nodes;
6185 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6186 if ( !dist2Nodes.empty() )
6187 return dist2Nodes.begin()->second;
6188 list<const SMDS_MeshNode*> nodes;
6189 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6191 double minSqDist = DBL_MAX;
6192 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6194 // sort leafs by their distance from thePnt
6195 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6196 TDistTreeMap treeMap;
6197 list< SMESH_OctreeNode* > treeList;
6198 list< SMESH_OctreeNode* >::iterator trIt;
6199 treeList.push_back( myOctreeNode );
6201 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6202 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6203 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6205 SMESH_OctreeNode* tree = *trIt;
6206 if ( !tree->isLeaf() ) // put children to the queue
6208 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6209 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6210 while ( cIt->more() )
6211 treeList.push_back( cIt->next() );
6213 else if ( tree->NbNodes() ) // put a tree to the treeMap
6215 const Bnd_B3d& box = tree->getBox();
6216 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6217 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6218 if ( !it_in.second ) // not unique distance to box center
6219 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6222 // find distance after which there is no sense to check tree's
6223 double sqLimit = DBL_MAX;
6224 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6225 if ( treeMap.size() > 5 ) {
6226 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6227 const Bnd_B3d& box = closestTree->getBox();
6228 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6229 sqLimit = limit * limit;
6231 // get all nodes from trees
6232 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6233 if ( sqDist_tree->first > sqLimit )
6235 SMESH_OctreeNode* tree = sqDist_tree->second;
6236 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6239 // find closest among nodes
6240 minSqDist = DBL_MAX;
6241 const SMDS_MeshNode* closestNode = 0;
6242 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6243 for ( ; nIt != nodes.end(); ++nIt ) {
6244 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6245 if ( minSqDist > sqDist ) {
6253 //---------------------------------------------------------------------
6257 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6259 //---------------------------------------------------------------------
6261 * \brief Return the node tree
6263 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6266 SMESH_OctreeNode* myOctreeNode;
6267 SMESHDS_Mesh* myMesh;
6268 double myHalfLeafSize; // max size of a leaf box
6271 //=======================================================================
6273 * \brief Return SMESH_NodeSearcher
6275 //=======================================================================
6277 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6279 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6282 // ========================================================================
6283 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6285 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6286 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6287 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6289 //=======================================================================
6291 * \brief Octal tree of bounding boxes of elements
6293 //=======================================================================
6295 class ElementBndBoxTree : public SMESH_Octree
6299 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6300 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6301 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6302 ~ElementBndBoxTree();
6305 ElementBndBoxTree() {}
6306 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6307 void buildChildrenData();
6308 Bnd_B3d* buildRootBox();
6310 //!< Bounding box of element
6311 struct ElementBox : public Bnd_B3d
6313 const SMDS_MeshElement* _element;
6314 int _refCount; // an ElementBox can be included in several tree branches
6315 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6317 vector< ElementBox* > _elements;
6320 //================================================================================
6322 * \brief ElementBndBoxTree creation
6324 //================================================================================
6326 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6327 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6329 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6330 _elements.reserve( nbElems );
6332 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6333 while ( elemIt->more() )
6334 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6336 if ( _elements.size() > MaxNbElemsInLeaf )
6342 //================================================================================
6346 //================================================================================
6348 ElementBndBoxTree::~ElementBndBoxTree()
6350 for ( int i = 0; i < _elements.size(); ++i )
6351 if ( --_elements[i]->_refCount <= 0 )
6352 delete _elements[i];
6355 //================================================================================
6357 * \brief Return the maximal box
6359 //================================================================================
6361 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6363 Bnd_B3d* box = new Bnd_B3d;
6364 for ( int i = 0; i < _elements.size(); ++i )
6365 box->Add( *_elements[i] );
6369 //================================================================================
6371 * \brief Redistrubute element boxes among children
6373 //================================================================================
6375 void ElementBndBoxTree::buildChildrenData()
6377 for ( int i = 0; i < _elements.size(); ++i )
6379 for (int j = 0; j < 8; j++)
6381 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6383 _elements[i]->_refCount++;
6384 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6387 _elements[i]->_refCount--;
6391 for (int j = 0; j < 8; j++)
6393 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6394 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6395 child->myIsLeaf = true;
6397 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6398 child->_elements.resize( child->_elements.size() ); // compact
6402 //================================================================================
6404 * \brief Return elements which can include the point
6406 //================================================================================
6408 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6409 TIDSortedElemSet& foundElems)
6411 if ( level() && getBox().IsOut( point.XYZ() ))
6416 for ( int i = 0; i < _elements.size(); ++i )
6417 if ( !_elements[i]->IsOut( point.XYZ() ))
6418 foundElems.insert( _elements[i]->_element );
6422 for (int i = 0; i < 8; i++)
6423 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6427 //================================================================================
6429 * \brief Return elements which can be intersected by the line
6431 //================================================================================
6433 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6434 TIDSortedElemSet& foundElems)
6436 if ( level() && getBox().IsOut( line ))
6441 for ( int i = 0; i < _elements.size(); ++i )
6442 if ( !_elements[i]->IsOut( line ))
6443 foundElems.insert( _elements[i]->_element );
6447 for (int i = 0; i < 8; i++)
6448 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6452 //================================================================================
6454 * \brief Construct the element box
6456 //================================================================================
6458 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6462 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6463 while ( nIt->more() )
6464 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6465 Enlarge( tolerance );
6470 //=======================================================================
6472 * \brief Implementation of search for the elements by point and
6473 * of classification of point in 2D mesh
6475 //=======================================================================
6477 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6479 SMESHDS_Mesh* _mesh;
6480 SMDS_ElemIteratorPtr _meshPartIt;
6481 ElementBndBoxTree* _ebbTree;
6482 SMESH_NodeSearcherImpl* _nodeSearcher;
6483 SMDSAbs_ElementType _elementType;
6485 bool _outerFacesFound;
6486 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6488 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6489 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6490 ~SMESH_ElementSearcherImpl()
6492 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6493 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6495 virtual int FindElementsByPoint(const gp_Pnt& point,
6496 SMDSAbs_ElementType type,
6497 vector< const SMDS_MeshElement* >& foundElements);
6498 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6500 void GetElementsNearLine( const gp_Ax1& line,
6501 SMDSAbs_ElementType type,
6502 vector< const SMDS_MeshElement* >& foundElems);
6503 double getTolerance();
6504 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6505 const double tolerance, double & param);
6506 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6507 bool isOuterBoundary(const SMDS_MeshElement* face) const
6509 return _outerFaces.empty() || _outerFaces.count(face);
6511 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6513 const SMDS_MeshElement* _face;
6515 bool _coincides; //!< the line lays in face plane
6516 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6517 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6519 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6522 TIDSortedElemSet _faces;
6523 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6524 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6528 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6530 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6531 << ", _coincides="<<i._coincides << ")";
6534 //=======================================================================
6536 * \brief define tolerance for search
6538 //=======================================================================
6540 double SMESH_ElementSearcherImpl::getTolerance()
6542 if ( _tolerance < 0 )
6544 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6547 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6549 double boxSize = _nodeSearcher->getTree()->maxSize();
6550 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6552 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6554 double boxSize = _ebbTree->maxSize();
6555 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6557 if ( _tolerance == 0 )
6559 // define tolerance by size of a most complex element
6560 int complexType = SMDSAbs_Volume;
6561 while ( complexType > SMDSAbs_All &&
6562 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6564 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6566 if ( complexType == int( SMDSAbs_Node ))
6568 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6570 if ( meshInfo.NbNodes() > 2 )
6571 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6575 SMDS_ElemIteratorPtr elemIt =
6576 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6577 const SMDS_MeshElement* elem = elemIt->next();
6578 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6579 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6580 while ( nodeIt->more() )
6582 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6583 elemSize = max( dist, elemSize );
6586 _tolerance = 1e-4 * elemSize;
6592 //================================================================================
6594 * \brief Find intersection of the line and an edge of face and return parameter on line
6596 //================================================================================
6598 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6599 const SMDS_MeshElement* face,
6606 GeomAPI_ExtremaCurveCurve anExtCC;
6607 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6609 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6610 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6612 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6613 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6614 anExtCC.Init( lineCurve, edge);
6615 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6617 Quantity_Parameter pl, pe;
6618 anExtCC.LowerDistanceParameters( pl, pe );
6620 if ( ++nbInts == 2 )
6624 if ( nbInts > 0 ) param /= nbInts;
6627 //================================================================================
6629 * \brief Find all faces belonging to the outer boundary of mesh
6631 //================================================================================
6633 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6635 if ( _outerFacesFound ) return;
6637 // Collect all outer faces by passing from one outer face to another via their links
6638 // and BTW find out if there are internal faces at all.
6640 // checked links and links where outer boundary meets internal one
6641 set< SMESH_TLink > visitedLinks, seamLinks;
6643 // links to treat with already visited faces sharing them
6644 list < TFaceLink > startLinks;
6646 // load startLinks with the first outerFace
6647 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6648 _outerFaces.insert( outerFace );
6650 TIDSortedElemSet emptySet;
6651 while ( !startLinks.empty() )
6653 const SMESH_TLink& link = startLinks.front()._link;
6654 TIDSortedElemSet& faces = startLinks.front()._faces;
6656 outerFace = *faces.begin();
6657 // find other faces sharing the link
6658 const SMDS_MeshElement* f;
6659 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6662 // select another outer face among the found
6663 const SMDS_MeshElement* outerFace2 = 0;
6664 if ( faces.size() == 2 )
6666 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6668 else if ( faces.size() > 2 )
6670 seamLinks.insert( link );
6672 // link direction within the outerFace
6673 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6674 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6675 int i1 = outerFace->GetNodeIndex( link.node1() );
6676 int i2 = outerFace->GetNodeIndex( link.node2() );
6677 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6678 if ( rev ) n1n2.Reverse();
6680 gp_XYZ ofNorm, fNorm;
6681 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6683 // direction from the link inside outerFace
6684 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6685 // sort all other faces by angle with the dirInOF
6686 map< double, const SMDS_MeshElement* > angle2Face;
6687 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6688 for ( ; face != faces.end(); ++face )
6690 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6692 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6693 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6694 if ( angle < 0 ) angle += 2*PI;
6695 angle2Face.insert( make_pair( angle, *face ));
6697 if ( !angle2Face.empty() )
6698 outerFace2 = angle2Face.begin()->second;
6701 // store the found outer face and add its links to continue seaching from
6704 _outerFaces.insert( outerFace );
6705 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6706 for ( int i = 0; i < nbNodes; ++i )
6708 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6709 if ( visitedLinks.insert( link2 ).second )
6710 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6713 startLinks.pop_front();
6715 _outerFacesFound = true;
6717 if ( !seamLinks.empty() )
6719 // There are internal boundaries touching the outher one,
6720 // find all faces of internal boundaries in order to find
6721 // faces of boundaries of holes, if any.
6726 _outerFaces.clear();
6730 //=======================================================================
6732 * \brief Find elements of given type where the given point is IN or ON.
6733 * Returns nb of found elements and elements them-selves.
6735 * 'ALL' type means elements of any type excluding nodes and 0D elements
6737 //=======================================================================
6739 int SMESH_ElementSearcherImpl::
6740 FindElementsByPoint(const gp_Pnt& point,
6741 SMDSAbs_ElementType type,
6742 vector< const SMDS_MeshElement* >& foundElements)
6744 foundElements.clear();
6746 double tolerance = getTolerance();
6748 // =================================================================================
6749 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6751 if ( !_nodeSearcher )
6752 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6754 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6755 if ( !closeNode ) return foundElements.size();
6757 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6758 return foundElements.size(); // to far from any node
6760 if ( type == SMDSAbs_Node )
6762 foundElements.push_back( closeNode );
6766 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6767 while ( elemIt->more() )
6768 foundElements.push_back( elemIt->next() );
6771 // =================================================================================
6772 else // elements more complex than 0D
6774 if ( !_ebbTree || _elementType != type )
6776 if ( _ebbTree ) delete _ebbTree;
6777 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6779 TIDSortedElemSet suspectElems;
6780 _ebbTree->getElementsNearPoint( point, suspectElems );
6781 TIDSortedElemSet::iterator elem = suspectElems.begin();
6782 for ( ; elem != suspectElems.end(); ++elem )
6783 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6784 foundElements.push_back( *elem );
6786 return foundElements.size();
6789 //================================================================================
6791 * \brief Classify the given point in the closed 2D mesh
6793 //================================================================================
6795 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6797 double tolerance = getTolerance();
6798 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6800 if ( _ebbTree ) delete _ebbTree;
6801 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6803 // Algo: analyse transition of a line starting at the point through mesh boundary;
6804 // try three lines parallel to axis of the coordinate system and perform rough
6805 // analysis. If solution is not clear perform thorough analysis.
6807 const int nbAxes = 3;
6808 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6809 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6810 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6811 multimap< int, int > nbInt2Axis; // to find the simplest case
6812 for ( int axis = 0; axis < nbAxes; ++axis )
6814 gp_Ax1 lineAxis( point, axisDir[axis]);
6815 gp_Lin line ( lineAxis );
6817 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6818 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6820 // Intersect faces with the line
6822 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6823 TIDSortedElemSet::iterator face = suspectFaces.begin();
6824 for ( ; face != suspectFaces.end(); ++face )
6828 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6829 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6831 // perform intersection
6832 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6833 if ( !intersection.IsDone() )
6835 if ( intersection.IsInQuadric() )
6837 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6839 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6841 gp_Pnt intersectionPoint = intersection.Point(1);
6842 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6843 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6846 // Analyse intersections roughly
6848 int nbInter = u2inters.size();
6852 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6853 if ( nbInter == 1 ) // not closed mesh
6854 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6856 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6859 if ( (f<0) == (l<0) )
6862 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6863 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6864 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6867 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6869 if ( _outerFacesFound ) break; // pass to thorough analysis
6871 } // three attempts - loop on CS axes
6873 // Analyse intersections thoroughly.
6874 // We make two loops maximum, on the first one we only exclude touching intersections,
6875 // on the second, if situation is still unclear, we gather and use information on
6876 // position of faces (internal or outer). If faces position is already gathered,
6877 // we make the second loop right away.
6879 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6881 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6882 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6884 int axis = nb_axis->second;
6885 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6887 gp_Ax1 lineAxis( point, axisDir[axis]);
6888 gp_Lin line ( lineAxis );
6890 // add tangent intersections to u2inters
6892 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6893 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6894 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6895 u2inters.insert(make_pair( param, *tgtInt ));
6896 tangentInters[ axis ].clear();
6898 // Count intersections before and after the point excluding touching ones.
6899 // If hasPositionInfo we count intersections of outer boundary only
6901 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6902 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6903 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6904 bool ok = ! u_int1->second._coincides;
6905 while ( ok && u_int1 != u2inters.end() )
6907 double u = u_int1->first;
6908 bool touchingInt = false;
6909 if ( ++u_int2 != u2inters.end() )
6911 // skip intersections at the same point (if the line passes through edge or node)
6913 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6919 // skip tangent intersections
6921 const SMDS_MeshElement* prevFace = u_int1->second._face;
6922 while ( ok && u_int2->second._coincides )
6924 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6930 ok = ( u_int2 != u2inters.end() );
6935 // skip intersections at the same point after tangent intersections
6938 double u2 = u_int2->first;
6940 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6946 // decide if we skipped a touching intersection
6947 if ( nbSamePnt + nbTgt > 0 )
6949 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6950 map< double, TInters >::iterator u_int = u_int1;
6951 for ( ; u_int != u_int2; ++u_int )
6953 if ( u_int->second._coincides ) continue;
6954 double dot = u_int->second._faceNorm * line.Direction();
6955 if ( dot > maxDot ) maxDot = dot;
6956 if ( dot < minDot ) minDot = dot;
6958 touchingInt = ( minDot*maxDot < 0 );
6963 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6974 u_int1 = u_int2; // to next intersection
6976 } // loop on intersections with one line
6980 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6983 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6986 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6987 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6989 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6992 if ( (f<0) == (l<0) )
6995 if ( hasPositionInfo )
6996 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6998 } // loop on intersections of the tree lines - thorough analysis
7000 if ( !hasPositionInfo )
7002 // gather info on faces position - is face in the outer boundary or not
7003 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7004 findOuterBoundary( u2inters.begin()->second._face );
7007 } // two attempts - with and w/o faces position info in the mesh
7009 return TopAbs_UNKNOWN;
7012 //=======================================================================
7014 * \brief Return elements possibly intersecting the line
7016 //=======================================================================
7018 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7019 SMDSAbs_ElementType type,
7020 vector< const SMDS_MeshElement* >& foundElems)
7022 if ( !_ebbTree || _elementType != type )
7024 if ( _ebbTree ) delete _ebbTree;
7025 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7027 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7028 _ebbTree->getElementsNearLine( line, suspectFaces );
7029 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7032 //=======================================================================
7034 * \brief Return SMESH_ElementSearcher
7036 //=======================================================================
7038 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7040 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7043 //=======================================================================
7045 * \brief Return SMESH_ElementSearcher
7047 //=======================================================================
7049 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7051 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7054 //=======================================================================
7056 * \brief Return true if the point is IN or ON of the element
7058 //=======================================================================
7060 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7062 if ( element->GetType() == SMDSAbs_Volume)
7064 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7067 // get ordered nodes
7069 vector< gp_XYZ > xyz;
7070 vector<const SMDS_MeshNode*> nodeList;
7072 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7073 if ( element->IsQuadratic() ) {
7074 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7075 nodeIt = f->interlacedNodesElemIterator();
7076 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7077 nodeIt = e->interlacedNodesElemIterator();
7079 while ( nodeIt->more() )
7081 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7082 xyz.push_back( TNodeXYZ(node) );
7083 nodeList.push_back(node);
7086 int i, nbNodes = element->NbNodes();
7088 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7090 // compute face normal
7091 gp_Vec faceNorm(0,0,0);
7092 xyz.push_back( xyz.front() );
7093 nodeList.push_back( nodeList.front() );
7094 for ( i = 0; i < nbNodes; ++i )
7096 gp_Vec edge1( xyz[i+1], xyz[i]);
7097 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7098 faceNorm += edge1 ^ edge2;
7100 double normSize = faceNorm.Magnitude();
7101 if ( normSize <= tol )
7103 // degenerated face: point is out if it is out of all face edges
7104 for ( i = 0; i < nbNodes; ++i )
7106 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7107 if ( !isOut( &edge, point, tol ))
7112 faceNorm /= normSize;
7114 // check if the point lays on face plane
7115 gp_Vec n2p( xyz[0], point );
7116 if ( fabs( n2p * faceNorm ) > tol )
7117 return true; // not on face plane
7119 // check if point is out of face boundary:
7120 // define it by closest transition of a ray point->infinity through face boundary
7121 // on the face plane.
7122 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7123 // to find intersections of the ray with the boundary.
7125 gp_Vec plnNorm = ray ^ faceNorm;
7126 normSize = plnNorm.Magnitude();
7127 if ( normSize <= tol ) return false; // point coincides with the first node
7128 plnNorm /= normSize;
7129 // for each node of the face, compute its signed distance to the plane
7130 vector<double> dist( nbNodes + 1);
7131 for ( i = 0; i < nbNodes; ++i )
7133 gp_Vec n2p( xyz[i], point );
7134 dist[i] = n2p * plnNorm;
7136 dist.back() = dist.front();
7137 // find the closest intersection
7139 double rClosest, distClosest = 1e100;;
7141 for ( i = 0; i < nbNodes; ++i )
7144 if ( fabs( dist[i]) < tol )
7146 else if ( fabs( dist[i+1]) < tol )
7148 else if ( dist[i] * dist[i+1] < 0 )
7149 r = dist[i] / ( dist[i] - dist[i+1] );
7151 continue; // no intersection
7152 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7153 gp_Vec p2int ( point, pInt);
7154 if ( p2int * ray > -tol ) // right half-space
7156 double intDist = p2int.SquareMagnitude();
7157 if ( intDist < distClosest )
7162 distClosest = intDist;
7167 return true; // no intesections - out
7169 // analyse transition
7170 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7171 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7172 gp_Vec p2int ( point, pClosest );
7173 bool out = (edgeNorm * p2int) < -tol;
7174 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7177 // ray pass through a face node; analyze transition through an adjacent edge
7178 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7179 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7180 gp_Vec edgeAdjacent( p1, p2 );
7181 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7182 bool out2 = (edgeNorm2 * p2int) < -tol;
7184 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7185 return covexCorner ? (out || out2) : (out && out2);
7187 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7189 // point is out of edge if it is NOT ON any straight part of edge
7190 // (we consider quadratic edge as being composed of two straight parts)
7191 for ( i = 1; i < nbNodes; ++i )
7193 gp_Vec edge( xyz[i-1], xyz[i]);
7194 gp_Vec n1p ( xyz[i-1], point);
7195 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7198 gp_Vec n2p( xyz[i], point );
7199 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7201 return false; // point is ON this part
7205 // Node or 0D element -------------------------------------------------------------------------
7207 gp_Vec n2p ( xyz[0], point );
7208 return n2p.Magnitude() <= tol;
7213 //=======================================================================
7214 //function : SimplifyFace
7216 //=======================================================================
7217 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7218 vector<const SMDS_MeshNode *>& poly_nodes,
7219 vector<int>& quantities) const
7221 int nbNodes = faceNodes.size();
7226 set<const SMDS_MeshNode*> nodeSet;
7228 // get simple seq of nodes
7229 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7230 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7231 int iSimple = 0, nbUnique = 0;
7233 simpleNodes[iSimple++] = faceNodes[0];
7235 for (int iCur = 1; iCur < nbNodes; iCur++) {
7236 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7237 simpleNodes[iSimple++] = faceNodes[iCur];
7238 if (nodeSet.insert( faceNodes[iCur] ).second)
7242 int nbSimple = iSimple;
7243 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7253 bool foundLoop = (nbSimple > nbUnique);
7256 set<const SMDS_MeshNode*> loopSet;
7257 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7258 const SMDS_MeshNode* n = simpleNodes[iSimple];
7259 if (!loopSet.insert( n ).second) {
7263 int iC = 0, curLast = iSimple;
7264 for (; iC < curLast; iC++) {
7265 if (simpleNodes[iC] == n) break;
7267 int loopLen = curLast - iC;
7269 // create sub-element
7271 quantities.push_back(loopLen);
7272 for (; iC < curLast; iC++) {
7273 poly_nodes.push_back(simpleNodes[iC]);
7276 // shift the rest nodes (place from the first loop position)
7277 for (iC = curLast + 1; iC < nbSimple; iC++) {
7278 simpleNodes[iC - loopLen] = simpleNodes[iC];
7280 nbSimple -= loopLen;
7283 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7284 } // while (foundLoop)
7288 quantities.push_back(iSimple);
7289 for (int i = 0; i < iSimple; i++)
7290 poly_nodes.push_back(simpleNodes[i]);
7296 //=======================================================================
7297 //function : MergeNodes
7298 //purpose : In each group, the cdr of nodes are substituted by the first one
7300 //=======================================================================
7302 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7304 MESSAGE("MergeNodes");
7305 myLastCreatedElems.Clear();
7306 myLastCreatedNodes.Clear();
7308 SMESHDS_Mesh* aMesh = GetMeshDS();
7310 TNodeNodeMap nodeNodeMap; // node to replace - new node
7311 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7312 list< int > rmElemIds, rmNodeIds;
7314 // Fill nodeNodeMap and elems
7316 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7317 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7318 list<const SMDS_MeshNode*>& nodes = *grIt;
7319 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7320 const SMDS_MeshNode* nToKeep = *nIt;
7321 //MESSAGE("node to keep " << nToKeep->GetID());
7322 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7323 const SMDS_MeshNode* nToRemove = *nIt;
7324 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7325 if ( nToRemove != nToKeep ) {
7326 //MESSAGE(" node to remove " << nToRemove->GetID());
7327 rmNodeIds.push_back( nToRemove->GetID() );
7328 AddToSameGroups( nToKeep, nToRemove, aMesh );
7331 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7332 while ( invElemIt->more() ) {
7333 const SMDS_MeshElement* elem = invElemIt->next();
7338 // Change element nodes or remove an element
7340 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7341 for ( ; eIt != elems.end(); eIt++ ) {
7342 const SMDS_MeshElement* elem = *eIt;
7343 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7344 int nbNodes = elem->NbNodes();
7345 int aShapeId = FindShape( elem );
7347 set<const SMDS_MeshNode*> nodeSet;
7348 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7349 int iUnique = 0, iCur = 0, nbRepl = 0;
7350 vector<int> iRepl( nbNodes );
7352 // get new seq of nodes
7353 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7354 while ( itN->more() ) {
7355 const SMDS_MeshNode* n =
7356 static_cast<const SMDS_MeshNode*>( itN->next() );
7358 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7359 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7361 // BUG 0020185: begin
7363 bool stopRecur = false;
7364 set<const SMDS_MeshNode*> nodesRecur;
7365 nodesRecur.insert(n);
7366 while (!stopRecur) {
7367 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7368 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7369 n = (*nnIt_i).second;
7370 if (!nodesRecur.insert(n).second) {
7371 // error: recursive dependancy
7380 iRepl[ nbRepl++ ] = iCur;
7382 curNodes[ iCur ] = n;
7383 bool isUnique = nodeSet.insert( n ).second;
7385 uniqueNodes[ iUnique++ ] = n;
7389 // Analyse element topology after replacement
7392 int nbUniqueNodes = nodeSet.size();
7393 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7394 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7395 // Polygons and Polyhedral volumes
7396 if (elem->IsPoly()) {
7398 if (elem->GetType() == SMDSAbs_Face) {
7400 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7402 for (; inode < nbNodes; inode++) {
7403 face_nodes[inode] = curNodes[inode];
7406 vector<const SMDS_MeshNode *> polygons_nodes;
7407 vector<int> quantities;
7408 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7411 for (int iface = 0; iface < nbNew; iface++) {
7412 int nbNodes = quantities[iface];
7413 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7414 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7415 poly_nodes[ii] = polygons_nodes[inode];
7417 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7418 myLastCreatedElems.Append(newElem);
7420 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7423 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7424 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7425 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7427 if (nbNew > 0) quid = nbNew - 1;
7428 vector<int> newquant(quantities.begin()+quid, quantities.end());
7429 const SMDS_MeshElement* newElem = 0;
7430 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7431 myLastCreatedElems.Append(newElem);
7432 if ( aShapeId && newElem )
7433 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7434 rmElemIds.push_back(elem->GetID());
7437 rmElemIds.push_back(elem->GetID());
7441 else if (elem->GetType() == SMDSAbs_Volume) {
7442 // Polyhedral volume
7443 if (nbUniqueNodes < 4) {
7444 rmElemIds.push_back(elem->GetID());
7447 // each face has to be analyzed in order to check volume validity
7448 const SMDS_VtkVolume* aPolyedre =
7449 dynamic_cast<const SMDS_VtkVolume*>( elem );
7451 int nbFaces = aPolyedre->NbFaces();
7453 vector<const SMDS_MeshNode *> poly_nodes;
7454 vector<int> quantities;
7456 for (int iface = 1; iface <= nbFaces; iface++) {
7457 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7458 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7460 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7461 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7462 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7463 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7464 faceNode = (*nnIt).second;
7466 faceNodes[inode - 1] = faceNode;
7469 SimplifyFace(faceNodes, poly_nodes, quantities);
7472 if (quantities.size() > 3) {
7473 // to be done: remove coincident faces
7476 if (quantities.size() > 3)
7478 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7479 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7480 const SMDS_MeshElement* newElem = 0;
7481 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7482 myLastCreatedElems.Append(newElem);
7483 if ( aShapeId && newElem )
7484 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7485 rmElemIds.push_back(elem->GetID());
7489 rmElemIds.push_back(elem->GetID());
7500 // TODO not all the possible cases are solved. Find something more generic?
7501 switch ( nbNodes ) {
7502 case 2: ///////////////////////////////////// EDGE
7503 isOk = false; break;
7504 case 3: ///////////////////////////////////// TRIANGLE
7505 isOk = false; break;
7507 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7509 else { //////////////////////////////////// QUADRANGLE
7510 if ( nbUniqueNodes < 3 )
7512 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7513 isOk = false; // opposite nodes stick
7514 //MESSAGE("isOk " << isOk);
7517 case 6: ///////////////////////////////////// PENTAHEDRON
7518 if ( nbUniqueNodes == 4 ) {
7519 // ---------------------------------> tetrahedron
7521 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7522 // all top nodes stick: reverse a bottom
7523 uniqueNodes[ 0 ] = curNodes [ 1 ];
7524 uniqueNodes[ 1 ] = curNodes [ 0 ];
7526 else if (nbRepl == 3 &&
7527 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7528 // all bottom nodes stick: set a top before
7529 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7530 uniqueNodes[ 0 ] = curNodes [ 3 ];
7531 uniqueNodes[ 1 ] = curNodes [ 4 ];
7532 uniqueNodes[ 2 ] = curNodes [ 5 ];
7534 else if (nbRepl == 4 &&
7535 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7536 // a lateral face turns into a line: reverse a bottom
7537 uniqueNodes[ 0 ] = curNodes [ 1 ];
7538 uniqueNodes[ 1 ] = curNodes [ 0 ];
7543 else if ( nbUniqueNodes == 5 ) {
7544 // PENTAHEDRON --------------------> 2 tetrahedrons
7545 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7546 // a bottom node sticks with a linked top one
7548 SMDS_MeshElement* newElem =
7549 aMesh->AddVolume(curNodes[ 3 ],
7552 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7553 myLastCreatedElems.Append(newElem);
7555 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7556 // 2. : reverse a bottom
7557 uniqueNodes[ 0 ] = curNodes [ 1 ];
7558 uniqueNodes[ 1 ] = curNodes [ 0 ];
7568 if(elem->IsQuadratic()) { // Quadratic quadrangle
7580 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7583 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7585 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7586 uniqueNodes[0] = curNodes[0];
7587 uniqueNodes[1] = curNodes[2];
7588 uniqueNodes[2] = curNodes[3];
7589 uniqueNodes[3] = curNodes[5];
7590 uniqueNodes[4] = curNodes[6];
7591 uniqueNodes[5] = curNodes[7];
7594 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7595 uniqueNodes[0] = curNodes[0];
7596 uniqueNodes[1] = curNodes[1];
7597 uniqueNodes[2] = curNodes[2];
7598 uniqueNodes[3] = curNodes[4];
7599 uniqueNodes[4] = curNodes[5];
7600 uniqueNodes[5] = curNodes[6];
7603 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7604 uniqueNodes[0] = curNodes[1];
7605 uniqueNodes[1] = curNodes[2];
7606 uniqueNodes[2] = curNodes[3];
7607 uniqueNodes[3] = curNodes[5];
7608 uniqueNodes[4] = curNodes[6];
7609 uniqueNodes[5] = curNodes[0];
7612 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7613 uniqueNodes[0] = curNodes[0];
7614 uniqueNodes[1] = curNodes[1];
7615 uniqueNodes[2] = curNodes[3];
7616 uniqueNodes[3] = curNodes[4];
7617 uniqueNodes[4] = curNodes[6];
7618 uniqueNodes[5] = curNodes[7];
7621 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7622 uniqueNodes[0] = curNodes[0];
7623 uniqueNodes[1] = curNodes[2];
7624 uniqueNodes[2] = curNodes[3];
7625 uniqueNodes[3] = curNodes[1];
7626 uniqueNodes[4] = curNodes[6];
7627 uniqueNodes[5] = curNodes[7];
7630 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7631 uniqueNodes[0] = curNodes[0];
7632 uniqueNodes[1] = curNodes[1];
7633 uniqueNodes[2] = curNodes[2];
7634 uniqueNodes[3] = curNodes[4];
7635 uniqueNodes[4] = curNodes[5];
7636 uniqueNodes[5] = curNodes[7];
7639 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7640 uniqueNodes[0] = curNodes[0];
7641 uniqueNodes[1] = curNodes[1];
7642 uniqueNodes[2] = curNodes[3];
7643 uniqueNodes[3] = curNodes[4];
7644 uniqueNodes[4] = curNodes[2];
7645 uniqueNodes[5] = curNodes[7];
7648 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7649 uniqueNodes[0] = curNodes[0];
7650 uniqueNodes[1] = curNodes[1];
7651 uniqueNodes[2] = curNodes[2];
7652 uniqueNodes[3] = curNodes[4];
7653 uniqueNodes[4] = curNodes[5];
7654 uniqueNodes[5] = curNodes[3];
7659 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7662 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7666 //////////////////////////////////// HEXAHEDRON
7668 SMDS_VolumeTool hexa (elem);
7669 hexa.SetExternalNormal();
7670 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7671 //////////////////////// ---> tetrahedron
7672 for ( int iFace = 0; iFace < 6; iFace++ ) {
7673 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7674 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7675 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7676 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7677 // one face turns into a point ...
7678 int iOppFace = hexa.GetOppFaceIndex( iFace );
7679 ind = hexa.GetFaceNodesIndices( iOppFace );
7681 iUnique = 2; // reverse a tetrahedron bottom
7682 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7683 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7685 else if ( iUnique >= 0 )
7686 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7688 if ( nbStick == 1 ) {
7689 // ... and the opposite one - into a triangle.
7691 ind = hexa.GetFaceNodesIndices( iFace );
7692 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7699 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7700 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7701 for ( int iFace = 0; iFace < 6; iFace++ ) {
7702 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7703 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7704 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7705 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7706 // one face turns into a point ...
7707 int iOppFace = hexa.GetOppFaceIndex( iFace );
7708 ind = hexa.GetFaceNodesIndices( iOppFace );
7710 iUnique = 2; // reverse a tetrahedron 1 bottom
7711 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7712 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7714 else if ( iUnique >= 0 )
7715 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7717 if ( nbStick == 0 ) {
7718 // ... and the opposite one is a quadrangle
7720 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7721 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7724 SMDS_MeshElement* newElem =
7725 aMesh->AddVolume(curNodes[ind[ 0 ]],
7728 curNodes[indTop[ 0 ]]);
7729 myLastCreatedElems.Append(newElem);
7731 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7738 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7739 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7740 // find indices of quad and tri faces
7741 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7742 for ( iFace = 0; iFace < 6; iFace++ ) {
7743 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7745 for ( iCur = 0; iCur < 4; iCur++ )
7746 nodeSet.insert( curNodes[ind[ iCur ]] );
7747 nbUniqueNodes = nodeSet.size();
7748 if ( nbUniqueNodes == 3 )
7749 iTriFace[ nbTri++ ] = iFace;
7750 else if ( nbUniqueNodes == 4 )
7751 iQuadFace[ nbQuad++ ] = iFace;
7753 if (nbQuad == 2 && nbTri == 4 &&
7754 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7755 // 2 opposite quadrangles stuck with a diagonal;
7756 // sample groups of merged indices: (0-4)(2-6)
7757 // --------------------------------------------> 2 tetrahedrons
7758 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7759 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7760 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7761 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7762 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7763 // stuck with 0-2 diagonal
7771 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7772 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7773 // stuck with 1-3 diagonal
7785 uniqueNodes[ 0 ] = curNodes [ i0 ];
7786 uniqueNodes[ 1 ] = curNodes [ i1d ];
7787 uniqueNodes[ 2 ] = curNodes [ i3d ];
7788 uniqueNodes[ 3 ] = curNodes [ i0t ];
7791 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7795 myLastCreatedElems.Append(newElem);
7797 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7800 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7801 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7802 // --------------------------------------------> prism
7803 // find 2 opposite triangles
7805 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7806 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7807 // find indices of kept and replaced nodes
7808 // and fill unique nodes of 2 opposite triangles
7809 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7810 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7811 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7812 // fill unique nodes
7815 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7816 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7817 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7819 // iCur of a linked node of the opposite face (make normals co-directed):
7820 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7821 // check that correspondent corners of triangles are linked
7822 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7825 uniqueNodes[ iUnique ] = n;
7826 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7835 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7841 } // switch ( nbNodes )
7843 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7846 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7847 // Change nodes of polyedre
7848 const SMDS_VtkVolume* aPolyedre =
7849 dynamic_cast<const SMDS_VtkVolume*>( elem );
7851 int nbFaces = aPolyedre->NbFaces();
7853 vector<const SMDS_MeshNode *> poly_nodes;
7854 vector<int> quantities (nbFaces);
7856 for (int iface = 1; iface <= nbFaces; iface++) {
7857 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7858 quantities[iface - 1] = nbFaceNodes;
7860 for (inode = 1; inode <= nbFaceNodes; inode++) {
7861 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7863 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7864 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7865 curNode = (*nnIt).second;
7867 poly_nodes.push_back(curNode);
7870 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7874 //int elemId = elem->GetID();
7875 //MESSAGE("Change regular element or polygon " << elemId);
7876 SMDSAbs_ElementType etyp = elem->GetType();
7877 uniqueNodes.resize(nbUniqueNodes);
7878 SMDS_MeshElement* newElem = 0;
7879 if (elem->GetEntityType() == SMDSEntity_Polygon)
7880 newElem = this->AddElement(uniqueNodes, etyp, true);
7882 newElem = this->AddElement(uniqueNodes, etyp, false);
7885 myLastCreatedElems.Append(newElem);
7887 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7889 aMesh->RemoveElement(elem);
7893 // Remove invalid regular element or invalid polygon
7894 //MESSAGE("Remove invalid " << elem->GetID());
7895 rmElemIds.push_back( elem->GetID() );
7898 } // loop on elements
7900 // Remove bad elements, then equal nodes (order important)
7902 Remove( rmElemIds, false );
7903 Remove( rmNodeIds, true );
7908 // ========================================================
7909 // class : SortableElement
7910 // purpose : allow sorting elements basing on their nodes
7911 // ========================================================
7912 class SortableElement : public set <const SMDS_MeshElement*>
7916 SortableElement( const SMDS_MeshElement* theElem )
7919 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7920 while ( nodeIt->more() )
7921 this->insert( nodeIt->next() );
7924 const SMDS_MeshElement* Get() const
7927 void Set(const SMDS_MeshElement* e) const
7932 mutable const SMDS_MeshElement* myElem;
7935 //=======================================================================
7936 //function : FindEqualElements
7937 //purpose : Return list of group of elements built on the same nodes.
7938 // Search among theElements or in the whole mesh if theElements is empty
7939 //=======================================================================
7940 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7941 TListOfListOfElementsID & theGroupsOfElementsID)
7943 myLastCreatedElems.Clear();
7944 myLastCreatedNodes.Clear();
7946 typedef set<const SMDS_MeshElement*> TElemsSet;
7947 typedef map< SortableElement, int > TMapOfNodeSet;
7948 typedef list<int> TGroupOfElems;
7951 if ( theElements.empty() )
7952 { // get all elements in the mesh
7953 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7954 while ( eIt->more() )
7955 elems.insert( elems.end(), eIt->next());
7958 elems = theElements;
7960 vector< TGroupOfElems > arrayOfGroups;
7961 TGroupOfElems groupOfElems;
7962 TMapOfNodeSet mapOfNodeSet;
7964 TElemsSet::iterator elemIt = elems.begin();
7965 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7966 const SMDS_MeshElement* curElem = *elemIt;
7967 SortableElement SE(curElem);
7970 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7971 if( !(pp.second) ) {
7972 TMapOfNodeSet::iterator& itSE = pp.first;
7973 ind = (*itSE).second;
7974 arrayOfGroups[ind].push_back(curElem->GetID());
7977 groupOfElems.clear();
7978 groupOfElems.push_back(curElem->GetID());
7979 arrayOfGroups.push_back(groupOfElems);
7984 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7985 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7986 groupOfElems = *groupIt;
7987 if ( groupOfElems.size() > 1 ) {
7988 groupOfElems.sort();
7989 theGroupsOfElementsID.push_back(groupOfElems);
7994 //=======================================================================
7995 //function : MergeElements
7996 //purpose : In each given group, substitute all elements by the first one.
7997 //=======================================================================
7999 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8001 myLastCreatedElems.Clear();
8002 myLastCreatedNodes.Clear();
8004 typedef list<int> TListOfIDs;
8005 TListOfIDs rmElemIds; // IDs of elems to remove
8007 SMESHDS_Mesh* aMesh = GetMeshDS();
8009 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8010 while ( groupsIt != theGroupsOfElementsID.end() ) {
8011 TListOfIDs& aGroupOfElemID = *groupsIt;
8012 aGroupOfElemID.sort();
8013 int elemIDToKeep = aGroupOfElemID.front();
8014 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8015 aGroupOfElemID.pop_front();
8016 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8017 while ( idIt != aGroupOfElemID.end() ) {
8018 int elemIDToRemove = *idIt;
8019 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8020 // add the kept element in groups of removed one (PAL15188)
8021 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8022 rmElemIds.push_back( elemIDToRemove );
8028 Remove( rmElemIds, false );
8031 //=======================================================================
8032 //function : MergeEqualElements
8033 //purpose : Remove all but one of elements built on the same nodes.
8034 //=======================================================================
8036 void SMESH_MeshEditor::MergeEqualElements()
8038 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8039 to merge equal elements in the whole mesh */
8040 TListOfListOfElementsID aGroupsOfElementsID;
8041 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8042 MergeElements(aGroupsOfElementsID);
8045 //=======================================================================
8046 //function : FindFaceInSet
8047 //purpose : Return a face having linked nodes n1 and n2 and which is
8048 // - not in avoidSet,
8049 // - in elemSet provided that !elemSet.empty()
8050 // i1 and i2 optionally returns indices of n1 and n2
8051 //=======================================================================
8053 const SMDS_MeshElement*
8054 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8055 const SMDS_MeshNode* n2,
8056 const TIDSortedElemSet& elemSet,
8057 const TIDSortedElemSet& avoidSet,
8063 const SMDS_MeshElement* face = 0;
8065 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8066 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8067 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8069 //MESSAGE("in while ( invElemIt->more() && !face )");
8070 const SMDS_MeshElement* elem = invElemIt->next();
8071 if (avoidSet.count( elem ))
8073 if ( !elemSet.empty() && !elemSet.count( elem ))
8076 i1 = elem->GetNodeIndex( n1 );
8077 // find a n2 linked to n1
8078 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8079 for ( int di = -1; di < 2 && !face; di += 2 )
8081 i2 = (i1+di+nbN) % nbN;
8082 if ( elem->GetNode( i2 ) == n2 )
8085 if ( !face && elem->IsQuadratic())
8087 // analysis for quadratic elements using all nodes
8088 const SMDS_VtkFace* F =
8089 dynamic_cast<const SMDS_VtkFace*>(elem);
8090 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8091 // use special nodes iterator
8092 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8093 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8094 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8096 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8097 if ( n1 == prevN && n2 == n )
8101 else if ( n2 == prevN && n1 == n )
8103 face = elem; swap( i1, i2 );
8109 if ( n1ind ) *n1ind = i1;
8110 if ( n2ind ) *n2ind = i2;
8114 //=======================================================================
8115 //function : findAdjacentFace
8117 //=======================================================================
8119 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8120 const SMDS_MeshNode* n2,
8121 const SMDS_MeshElement* elem)
8123 TIDSortedElemSet elemSet, avoidSet;
8125 avoidSet.insert ( elem );
8126 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8129 //=======================================================================
8130 //function : FindFreeBorder
8132 //=======================================================================
8134 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8136 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8137 const SMDS_MeshNode* theSecondNode,
8138 const SMDS_MeshNode* theLastNode,
8139 list< const SMDS_MeshNode* > & theNodes,
8140 list< const SMDS_MeshElement* >& theFaces)
8142 if ( !theFirstNode || !theSecondNode )
8144 // find border face between theFirstNode and theSecondNode
8145 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8149 theFaces.push_back( curElem );
8150 theNodes.push_back( theFirstNode );
8151 theNodes.push_back( theSecondNode );
8153 //vector<const SMDS_MeshNode*> nodes;
8154 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8155 TIDSortedElemSet foundElems;
8156 bool needTheLast = ( theLastNode != 0 );
8158 while ( nStart != theLastNode ) {
8159 if ( nStart == theFirstNode )
8160 return !needTheLast;
8162 // find all free border faces sharing form nStart
8164 list< const SMDS_MeshElement* > curElemList;
8165 list< const SMDS_MeshNode* > nStartList;
8166 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8167 while ( invElemIt->more() ) {
8168 const SMDS_MeshElement* e = invElemIt->next();
8169 if ( e == curElem || foundElems.insert( e ).second ) {
8171 int iNode = 0, nbNodes = e->NbNodes();
8172 //const SMDS_MeshNode* nodes[nbNodes+1];
8173 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8175 if(e->IsQuadratic()) {
8176 const SMDS_VtkFace* F =
8177 dynamic_cast<const SMDS_VtkFace*>(e);
8178 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8179 // use special nodes iterator
8180 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8181 while( anIter->more() ) {
8182 nodes[ iNode++ ] = cast2Node(anIter->next());
8186 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8187 while ( nIt->more() )
8188 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8190 nodes[ iNode ] = nodes[ 0 ];
8192 for ( iNode = 0; iNode < nbNodes; iNode++ )
8193 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8194 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8195 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8197 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8198 curElemList.push_back( e );
8202 // analyse the found
8204 int nbNewBorders = curElemList.size();
8205 if ( nbNewBorders == 0 ) {
8206 // no free border furthermore
8207 return !needTheLast;
8209 else if ( nbNewBorders == 1 ) {
8210 // one more element found
8212 nStart = nStartList.front();
8213 curElem = curElemList.front();
8214 theFaces.push_back( curElem );
8215 theNodes.push_back( nStart );
8218 // several continuations found
8219 list< const SMDS_MeshElement* >::iterator curElemIt;
8220 list< const SMDS_MeshNode* >::iterator nStartIt;
8221 // check if one of them reached the last node
8222 if ( needTheLast ) {
8223 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8224 curElemIt!= curElemList.end();
8225 curElemIt++, nStartIt++ )
8226 if ( *nStartIt == theLastNode ) {
8227 theFaces.push_back( *curElemIt );
8228 theNodes.push_back( *nStartIt );
8232 // find the best free border by the continuations
8233 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8234 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8235 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8236 curElemIt!= curElemList.end();
8237 curElemIt++, nStartIt++ )
8239 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8240 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8241 // find one more free border
8242 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8246 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8247 // choice: clear a worse one
8248 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8249 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8250 contNodes[ iWorse ].clear();
8251 contFaces[ iWorse ].clear();
8254 if ( contNodes[0].empty() && contNodes[1].empty() )
8257 // append the best free border
8258 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8259 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8260 theNodes.pop_back(); // remove nIgnore
8261 theNodes.pop_back(); // remove nStart
8262 theFaces.pop_back(); // remove curElem
8263 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8264 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8265 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8266 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8269 } // several continuations found
8270 } // while ( nStart != theLastNode )
8275 //=======================================================================
8276 //function : CheckFreeBorderNodes
8277 //purpose : Return true if the tree nodes are on a free border
8278 //=======================================================================
8280 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8281 const SMDS_MeshNode* theNode2,
8282 const SMDS_MeshNode* theNode3)
8284 list< const SMDS_MeshNode* > nodes;
8285 list< const SMDS_MeshElement* > faces;
8286 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8289 //=======================================================================
8290 //function : SewFreeBorder
8292 //=======================================================================
8294 SMESH_MeshEditor::Sew_Error
8295 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8296 const SMDS_MeshNode* theBordSecondNode,
8297 const SMDS_MeshNode* theBordLastNode,
8298 const SMDS_MeshNode* theSideFirstNode,
8299 const SMDS_MeshNode* theSideSecondNode,
8300 const SMDS_MeshNode* theSideThirdNode,
8301 const bool theSideIsFreeBorder,
8302 const bool toCreatePolygons,
8303 const bool toCreatePolyedrs)
8305 myLastCreatedElems.Clear();
8306 myLastCreatedNodes.Clear();
8308 MESSAGE("::SewFreeBorder()");
8309 Sew_Error aResult = SEW_OK;
8311 // ====================================
8312 // find side nodes and elements
8313 // ====================================
8315 list< const SMDS_MeshNode* > nSide[ 2 ];
8316 list< const SMDS_MeshElement* > eSide[ 2 ];
8317 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8318 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8322 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8323 nSide[0], eSide[0])) {
8324 MESSAGE(" Free Border 1 not found " );
8325 aResult = SEW_BORDER1_NOT_FOUND;
8327 if (theSideIsFreeBorder) {
8330 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8331 nSide[1], eSide[1])) {
8332 MESSAGE(" Free Border 2 not found " );
8333 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8336 if ( aResult != SEW_OK )
8339 if (!theSideIsFreeBorder) {
8343 // -------------------------------------------------------------------------
8345 // 1. If nodes to merge are not coincident, move nodes of the free border
8346 // from the coord sys defined by the direction from the first to last
8347 // nodes of the border to the correspondent sys of the side 2
8348 // 2. On the side 2, find the links most co-directed with the correspondent
8349 // links of the free border
8350 // -------------------------------------------------------------------------
8352 // 1. Since sewing may break if there are volumes to split on the side 2,
8353 // we wont move nodes but just compute new coordinates for them
8354 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8355 TNodeXYZMap nBordXYZ;
8356 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8357 list< const SMDS_MeshNode* >::iterator nBordIt;
8359 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8360 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8361 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8362 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8363 double tol2 = 1.e-8;
8364 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8365 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8366 // Need node movement.
8368 // find X and Z axes to create trsf
8369 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8371 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8373 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8376 gp_Ax3 toBordAx( Pb1, Zb, X );
8377 gp_Ax3 fromSideAx( Ps1, Zs, X );
8378 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8380 gp_Trsf toBordSys, fromSide2Sys;
8381 toBordSys.SetTransformation( toBordAx );
8382 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8383 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8386 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8387 const SMDS_MeshNode* n = *nBordIt;
8388 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8389 toBordSys.Transforms( xyz );
8390 fromSide2Sys.Transforms( xyz );
8391 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8395 // just insert nodes XYZ in the nBordXYZ map
8396 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8397 const SMDS_MeshNode* n = *nBordIt;
8398 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8402 // 2. On the side 2, find the links most co-directed with the correspondent
8403 // links of the free border
8405 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8406 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8407 sideNodes.push_back( theSideFirstNode );
8409 bool hasVolumes = false;
8410 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8411 set<long> foundSideLinkIDs, checkedLinkIDs;
8412 SMDS_VolumeTool volume;
8413 //const SMDS_MeshNode* faceNodes[ 4 ];
8415 const SMDS_MeshNode* sideNode;
8416 const SMDS_MeshElement* sideElem;
8417 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8418 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8419 nBordIt = bordNodes.begin();
8421 // border node position and border link direction to compare with
8422 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8423 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8424 // choose next side node by link direction or by closeness to
8425 // the current border node:
8426 bool searchByDir = ( *nBordIt != theBordLastNode );
8428 // find the next node on the Side 2
8430 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8432 checkedLinkIDs.clear();
8433 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8435 // loop on inverse elements of current node (prevSideNode) on the Side 2
8436 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8437 while ( invElemIt->more() )
8439 const SMDS_MeshElement* elem = invElemIt->next();
8440 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8441 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8442 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8443 bool isVolume = volume.Set( elem );
8444 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8445 if ( isVolume ) // --volume
8447 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8448 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8449 if(elem->IsQuadratic()) {
8450 const SMDS_VtkFace* F =
8451 dynamic_cast<const SMDS_VtkFace*>(elem);
8452 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8453 // use special nodes iterator
8454 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8455 while( anIter->more() ) {
8456 nodes[ iNode ] = cast2Node(anIter->next());
8457 if ( nodes[ iNode++ ] == prevSideNode )
8458 iPrevNode = iNode - 1;
8462 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8463 while ( nIt->more() ) {
8464 nodes[ iNode ] = cast2Node( nIt->next() );
8465 if ( nodes[ iNode++ ] == prevSideNode )
8466 iPrevNode = iNode - 1;
8469 // there are 2 links to check
8474 // loop on links, to be precise, on the second node of links
8475 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8476 const SMDS_MeshNode* n = nodes[ iNode ];
8478 if ( !volume.IsLinked( n, prevSideNode ))
8482 if ( iNode ) // a node before prevSideNode
8483 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8484 else // a node after prevSideNode
8485 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8487 // check if this link was already used
8488 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8489 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8490 if (!isJustChecked &&
8491 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8493 // test a link geometrically
8494 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8495 bool linkIsBetter = false;
8496 double dot = 0.0, dist = 0.0;
8497 if ( searchByDir ) { // choose most co-directed link
8498 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8499 linkIsBetter = ( dot > maxDot );
8501 else { // choose link with the node closest to bordPos
8502 dist = ( nextXYZ - bordPos ).SquareModulus();
8503 linkIsBetter = ( dist < minDist );
8505 if ( linkIsBetter ) {
8514 } // loop on inverse elements of prevSideNode
8517 MESSAGE(" Cant find path by links of the Side 2 ");
8518 return SEW_BAD_SIDE_NODES;
8520 sideNodes.push_back( sideNode );
8521 sideElems.push_back( sideElem );
8522 foundSideLinkIDs.insert ( linkID );
8523 prevSideNode = sideNode;
8525 if ( *nBordIt == theBordLastNode )
8526 searchByDir = false;
8528 // find the next border link to compare with
8529 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8530 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8531 // move to next border node if sideNode is before forward border node (bordPos)
8532 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8533 prevBordNode = *nBordIt;
8535 bordPos = nBordXYZ[ *nBordIt ];
8536 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8537 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8541 while ( sideNode != theSideSecondNode );
8543 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8544 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8545 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8547 } // end nodes search on the side 2
8549 // ============================
8550 // sew the border to the side 2
8551 // ============================
8553 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8554 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8556 TListOfListOfNodes nodeGroupsToMerge;
8557 if ( nbNodes[0] == nbNodes[1] ||
8558 ( theSideIsFreeBorder && !theSideThirdNode)) {
8560 // all nodes are to be merged
8562 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8563 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8564 nIt[0]++, nIt[1]++ )
8566 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8567 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8568 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8573 // insert new nodes into the border and the side to get equal nb of segments
8575 // get normalized parameters of nodes on the borders
8576 //double param[ 2 ][ maxNbNodes ];
8578 param[0] = new double [ maxNbNodes ];
8579 param[1] = new double [ maxNbNodes ];
8581 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8582 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8583 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8584 const SMDS_MeshNode* nPrev = *nIt;
8585 double bordLength = 0;
8586 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8587 const SMDS_MeshNode* nCur = *nIt;
8588 gp_XYZ segment (nCur->X() - nPrev->X(),
8589 nCur->Y() - nPrev->Y(),
8590 nCur->Z() - nPrev->Z());
8591 double segmentLen = segment.Modulus();
8592 bordLength += segmentLen;
8593 param[ iBord ][ iNode ] = bordLength;
8596 // normalize within [0,1]
8597 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8598 param[ iBord ][ iNode ] /= bordLength;
8602 // loop on border segments
8603 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8604 int i[ 2 ] = { 0, 0 };
8605 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8606 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8608 TElemOfNodeListMap insertMap;
8609 TElemOfNodeListMap::iterator insertMapIt;
8611 // key: elem to insert nodes into
8612 // value: 2 nodes to insert between + nodes to be inserted
8614 bool next[ 2 ] = { false, false };
8616 // find min adjacent segment length after sewing
8617 double nextParam = 10., prevParam = 0;
8618 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8619 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8620 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8621 if ( i[ iBord ] > 0 )
8622 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8624 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8625 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8626 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8628 // choose to insert or to merge nodes
8629 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8630 if ( Abs( du ) <= minSegLen * 0.2 ) {
8633 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8634 const SMDS_MeshNode* n0 = *nIt[0];
8635 const SMDS_MeshNode* n1 = *nIt[1];
8636 nodeGroupsToMerge.back().push_back( n1 );
8637 nodeGroupsToMerge.back().push_back( n0 );
8638 // position of node of the border changes due to merge
8639 param[ 0 ][ i[0] ] += du;
8640 // move n1 for the sake of elem shape evaluation during insertion.
8641 // n1 will be removed by MergeNodes() anyway
8642 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8643 next[0] = next[1] = true;
8648 int intoBord = ( du < 0 ) ? 0 : 1;
8649 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8650 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8651 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8652 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8653 if ( intoBord == 1 ) {
8654 // move node of the border to be on a link of elem of the side
8655 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8656 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8657 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8658 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8659 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8661 insertMapIt = insertMap.find( elem );
8662 bool notFound = ( insertMapIt == insertMap.end() );
8663 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8665 // insert into another link of the same element:
8666 // 1. perform insertion into the other link of the elem
8667 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8668 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8669 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8670 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8671 // 2. perform insertion into the link of adjacent faces
8673 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8675 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8679 if (toCreatePolyedrs) {
8680 // perform insertion into the links of adjacent volumes
8681 UpdateVolumes(n12, n22, nodeList);
8683 // 3. find an element appeared on n1 and n2 after the insertion
8684 insertMap.erase( elem );
8685 elem = findAdjacentFace( n1, n2, 0 );
8687 if ( notFound || otherLink ) {
8688 // add element and nodes of the side into the insertMap
8689 insertMapIt = insertMap.insert
8690 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8691 (*insertMapIt).second.push_back( n1 );
8692 (*insertMapIt).second.push_back( n2 );
8694 // add node to be inserted into elem
8695 (*insertMapIt).second.push_back( nIns );
8696 next[ 1 - intoBord ] = true;
8699 // go to the next segment
8700 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8701 if ( next[ iBord ] ) {
8702 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8704 nPrev[ iBord ] = *nIt[ iBord ];
8705 nIt[ iBord ]++; i[ iBord ]++;
8709 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8711 // perform insertion of nodes into elements
8713 for (insertMapIt = insertMap.begin();
8714 insertMapIt != insertMap.end();
8717 const SMDS_MeshElement* elem = (*insertMapIt).first;
8718 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8719 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8720 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8722 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8724 if ( !theSideIsFreeBorder ) {
8725 // look for and insert nodes into the faces adjacent to elem
8727 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8729 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8734 if (toCreatePolyedrs) {
8735 // perform insertion into the links of adjacent volumes
8736 UpdateVolumes(n1, n2, nodeList);
8742 } // end: insert new nodes
8744 MergeNodes ( nodeGroupsToMerge );
8749 //=======================================================================
8750 //function : InsertNodesIntoLink
8751 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8752 // and theBetweenNode2 and split theElement
8753 //=======================================================================
8755 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8756 const SMDS_MeshNode* theBetweenNode1,
8757 const SMDS_MeshNode* theBetweenNode2,
8758 list<const SMDS_MeshNode*>& theNodesToInsert,
8759 const bool toCreatePoly)
8761 if ( theFace->GetType() != SMDSAbs_Face ) return;
8763 // find indices of 2 link nodes and of the rest nodes
8764 int iNode = 0, il1, il2, i3, i4;
8765 il1 = il2 = i3 = i4 = -1;
8766 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8767 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8769 if(theFace->IsQuadratic()) {
8770 const SMDS_VtkFace* F =
8771 dynamic_cast<const SMDS_VtkFace*>(theFace);
8772 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8773 // use special nodes iterator
8774 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8775 while( anIter->more() ) {
8776 const SMDS_MeshNode* n = cast2Node(anIter->next());
8777 if ( n == theBetweenNode1 )
8779 else if ( n == theBetweenNode2 )
8785 nodes[ iNode++ ] = n;
8789 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8790 while ( nodeIt->more() ) {
8791 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8792 if ( n == theBetweenNode1 )
8794 else if ( n == theBetweenNode2 )
8800 nodes[ iNode++ ] = n;
8803 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8806 // arrange link nodes to go one after another regarding the face orientation
8807 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8808 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8813 aNodesToInsert.reverse();
8815 // check that not link nodes of a quadrangles are in good order
8816 int nbFaceNodes = theFace->NbNodes();
8817 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8823 if (toCreatePoly || theFace->IsPoly()) {
8826 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8828 // add nodes of face up to first node of link
8831 if(theFace->IsQuadratic()) {
8832 const SMDS_VtkFace* F =
8833 dynamic_cast<const SMDS_VtkFace*>(theFace);
8834 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8835 // use special nodes iterator
8836 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8837 while( anIter->more() && !isFLN ) {
8838 const SMDS_MeshNode* n = cast2Node(anIter->next());
8839 poly_nodes[iNode++] = n;
8840 if (n == nodes[il1]) {
8844 // add nodes to insert
8845 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8846 for (; nIt != aNodesToInsert.end(); nIt++) {
8847 poly_nodes[iNode++] = *nIt;
8849 // add nodes of face starting from last node of link
8850 while ( anIter->more() ) {
8851 poly_nodes[iNode++] = cast2Node(anIter->next());
8855 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8856 while ( nodeIt->more() && !isFLN ) {
8857 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8858 poly_nodes[iNode++] = n;
8859 if (n == nodes[il1]) {
8863 // add nodes to insert
8864 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8865 for (; nIt != aNodesToInsert.end(); nIt++) {
8866 poly_nodes[iNode++] = *nIt;
8868 // add nodes of face starting from last node of link
8869 while ( nodeIt->more() ) {
8870 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8871 poly_nodes[iNode++] = n;
8875 // edit or replace the face
8876 SMESHDS_Mesh *aMesh = GetMeshDS();
8878 if (theFace->IsPoly()) {
8879 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8882 int aShapeId = FindShape( theFace );
8884 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8885 myLastCreatedElems.Append(newElem);
8886 if ( aShapeId && newElem )
8887 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8889 aMesh->RemoveElement(theFace);
8894 SMESHDS_Mesh *aMesh = GetMeshDS();
8895 if( !theFace->IsQuadratic() ) {
8897 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8898 int nbLinkNodes = 2 + aNodesToInsert.size();
8899 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8900 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8901 linkNodes[ 0 ] = nodes[ il1 ];
8902 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8903 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8904 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8905 linkNodes[ iNode++ ] = *nIt;
8907 // decide how to split a quadrangle: compare possible variants
8908 // and choose which of splits to be a quadrangle
8909 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8910 if ( nbFaceNodes == 3 ) {
8911 iBestQuad = nbSplits;
8914 else if ( nbFaceNodes == 4 ) {
8915 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8916 double aBestRate = DBL_MAX;
8917 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8919 double aBadRate = 0;
8920 // evaluate elements quality
8921 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8922 if ( iSplit == iQuad ) {
8923 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8927 aBadRate += getBadRate( &quad, aCrit );
8930 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8932 nodes[ iSplit < iQuad ? i4 : i3 ]);
8933 aBadRate += getBadRate( &tria, aCrit );
8937 if ( aBadRate < aBestRate ) {
8939 aBestRate = aBadRate;
8944 // create new elements
8945 int aShapeId = FindShape( theFace );
8948 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8949 SMDS_MeshElement* newElem = 0;
8950 if ( iSplit == iBestQuad )
8951 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8956 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8958 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8959 myLastCreatedElems.Append(newElem);
8960 if ( aShapeId && newElem )
8961 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8964 // change nodes of theFace
8965 const SMDS_MeshNode* newNodes[ 4 ];
8966 newNodes[ 0 ] = linkNodes[ i1 ];
8967 newNodes[ 1 ] = linkNodes[ i2 ];
8968 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8969 newNodes[ 3 ] = nodes[ i4 ];
8970 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8971 const SMDS_MeshElement* newElem = 0;
8972 if (iSplit == iBestQuad)
8973 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8975 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8976 myLastCreatedElems.Append(newElem);
8977 if ( aShapeId && newElem )
8978 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8979 } // end if(!theFace->IsQuadratic())
8980 else { // theFace is quadratic
8981 // we have to split theFace on simple triangles and one simple quadrangle
8983 int nbshift = tmp*2;
8984 // shift nodes in nodes[] by nbshift
8986 for(i=0; i<nbshift; i++) {
8987 const SMDS_MeshNode* n = nodes[0];
8988 for(j=0; j<nbFaceNodes-1; j++) {
8989 nodes[j] = nodes[j+1];
8991 nodes[nbFaceNodes-1] = n;
8993 il1 = il1 - nbshift;
8994 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8995 // n0 n1 n2 n0 n1 n2
8996 // +-----+-----+ +-----+-----+
9005 // create new elements
9006 int aShapeId = FindShape( theFace );
9009 if(nbFaceNodes==6) { // quadratic triangle
9010 SMDS_MeshElement* newElem =
9011 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9012 myLastCreatedElems.Append(newElem);
9013 if ( aShapeId && newElem )
9014 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9015 if(theFace->IsMediumNode(nodes[il1])) {
9016 // create quadrangle
9017 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9018 myLastCreatedElems.Append(newElem);
9019 if ( aShapeId && newElem )
9020 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9026 // create quadrangle
9027 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9028 myLastCreatedElems.Append(newElem);
9029 if ( aShapeId && newElem )
9030 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9036 else { // nbFaceNodes==8 - quadratic quadrangle
9037 SMDS_MeshElement* newElem =
9038 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9039 myLastCreatedElems.Append(newElem);
9040 if ( aShapeId && newElem )
9041 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9042 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9043 myLastCreatedElems.Append(newElem);
9044 if ( aShapeId && newElem )
9045 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9046 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9047 myLastCreatedElems.Append(newElem);
9048 if ( aShapeId && newElem )
9049 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9050 if(theFace->IsMediumNode(nodes[il1])) {
9051 // create quadrangle
9052 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9053 myLastCreatedElems.Append(newElem);
9054 if ( aShapeId && newElem )
9055 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9061 // create quadrangle
9062 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9063 myLastCreatedElems.Append(newElem);
9064 if ( aShapeId && newElem )
9065 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9071 // create needed triangles using n1,n2,n3 and inserted nodes
9072 int nbn = 2 + aNodesToInsert.size();
9073 //const SMDS_MeshNode* aNodes[nbn];
9074 vector<const SMDS_MeshNode*> aNodes(nbn);
9075 aNodes[0] = nodes[n1];
9076 aNodes[nbn-1] = nodes[n2];
9077 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9078 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9079 aNodes[iNode++] = *nIt;
9081 for(i=1; i<nbn; i++) {
9082 SMDS_MeshElement* newElem =
9083 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9084 myLastCreatedElems.Append(newElem);
9085 if ( aShapeId && newElem )
9086 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9090 aMesh->RemoveElement(theFace);
9093 //=======================================================================
9094 //function : UpdateVolumes
9096 //=======================================================================
9097 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9098 const SMDS_MeshNode* theBetweenNode2,
9099 list<const SMDS_MeshNode*>& theNodesToInsert)
9101 myLastCreatedElems.Clear();
9102 myLastCreatedNodes.Clear();
9104 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9105 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9106 const SMDS_MeshElement* elem = invElemIt->next();
9108 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9109 SMDS_VolumeTool aVolume (elem);
9110 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9113 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9114 int iface, nbFaces = aVolume.NbFaces();
9115 vector<const SMDS_MeshNode *> poly_nodes;
9116 vector<int> quantities (nbFaces);
9118 for (iface = 0; iface < nbFaces; iface++) {
9119 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9120 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9121 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9123 for (int inode = 0; inode < nbFaceNodes; inode++) {
9124 poly_nodes.push_back(faceNodes[inode]);
9126 if (nbInserted == 0) {
9127 if (faceNodes[inode] == theBetweenNode1) {
9128 if (faceNodes[inode + 1] == theBetweenNode2) {
9129 nbInserted = theNodesToInsert.size();
9131 // add nodes to insert
9132 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9133 for (; nIt != theNodesToInsert.end(); nIt++) {
9134 poly_nodes.push_back(*nIt);
9138 else if (faceNodes[inode] == theBetweenNode2) {
9139 if (faceNodes[inode + 1] == theBetweenNode1) {
9140 nbInserted = theNodesToInsert.size();
9142 // add nodes to insert in reversed order
9143 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9145 for (; nIt != theNodesToInsert.begin(); nIt--) {
9146 poly_nodes.push_back(*nIt);
9148 poly_nodes.push_back(*nIt);
9155 quantities[iface] = nbFaceNodes + nbInserted;
9158 // Replace or update the volume
9159 SMESHDS_Mesh *aMesh = GetMeshDS();
9161 if (elem->IsPoly()) {
9162 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9166 int aShapeId = FindShape( elem );
9168 SMDS_MeshElement* newElem =
9169 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9170 myLastCreatedElems.Append(newElem);
9171 if (aShapeId && newElem)
9172 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9174 aMesh->RemoveElement(elem);
9179 //=======================================================================
9181 * \brief Convert elements contained in a submesh to quadratic
9182 * \retval int - nb of checked elements
9184 //=======================================================================
9186 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9187 SMESH_MesherHelper& theHelper,
9188 const bool theForce3d)
9191 if( !theSm ) return nbElem;
9193 vector<int> nbNodeInFaces;
9194 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9195 while(ElemItr->more())
9198 const SMDS_MeshElement* elem = ElemItr->next();
9199 if( !elem || elem->IsQuadratic() ) continue;
9201 int id = elem->GetID();
9202 //MESSAGE("elem " << id);
9203 id = 0; // get a free number for new elements
9204 int nbNodes = elem->NbNodes();
9205 SMDSAbs_ElementType aType = elem->GetType();
9207 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9208 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9209 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9211 const SMDS_MeshElement* NewElem = 0;
9217 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9225 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9228 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9231 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9236 case SMDSAbs_Volume :
9241 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9244 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9247 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9250 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9251 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9254 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9261 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9263 theSm->AddElement( NewElem );
9265 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9267 // if (!GetMeshDS()->isCompacted())
9268 // GetMeshDS()->compactMesh();
9272 //=======================================================================
9273 //function : ConvertToQuadratic
9275 //=======================================================================
9276 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9278 SMESHDS_Mesh* meshDS = GetMeshDS();
9280 SMESH_MesherHelper aHelper(*myMesh);
9281 aHelper.SetIsQuadratic( true );
9283 int nbCheckedElems = 0;
9284 if ( myMesh->HasShapeToMesh() )
9286 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9288 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9289 while ( smIt->more() ) {
9290 SMESH_subMesh* sm = smIt->next();
9291 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9292 aHelper.SetSubShape( sm->GetSubShape() );
9293 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9298 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9299 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9301 SMESHDS_SubMesh *smDS = 0;
9302 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9303 while(aEdgeItr->more())
9305 const SMDS_MeshEdge* edge = aEdgeItr->next();
9306 if(edge && !edge->IsQuadratic())
9308 int id = edge->GetID();
9309 //MESSAGE("edge->GetID() " << id);
9310 const SMDS_MeshNode* n1 = edge->GetNode(0);
9311 const SMDS_MeshNode* n2 = edge->GetNode(1);
9313 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9315 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9316 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9319 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9320 while(aFaceItr->more())
9322 const SMDS_MeshFace* face = aFaceItr->next();
9323 if(!face || face->IsQuadratic() ) continue;
9325 int id = face->GetID();
9326 int nbNodes = face->NbNodes();
9327 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9329 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9331 SMDS_MeshFace * NewFace = 0;
9335 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9338 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9341 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9343 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9345 vector<int> nbNodeInFaces;
9346 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9347 while(aVolumeItr->more())
9349 const SMDS_MeshVolume* volume = aVolumeItr->next();
9350 if(!volume || volume->IsQuadratic() ) continue;
9352 int id = volume->GetID();
9353 int nbNodes = volume->NbNodes();
9354 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9355 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9356 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9358 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9360 SMDS_MeshVolume * NewVolume = 0;
9364 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9365 nodes[3], id, theForce3d );
9368 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9369 nodes[3], nodes[4], id, theForce3d);
9372 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9373 nodes[3], nodes[4], nodes[5], id, theForce3d);
9376 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9377 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9380 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9382 ReplaceElemInGroups(volume, NewVolume, meshDS);
9386 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9387 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9388 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9389 aHelper.FixQuadraticElements();
9391 if (!GetMeshDS()->isCompacted())
9392 GetMeshDS()->compactMesh();
9395 //=======================================================================
9397 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9398 * \retval int - nb of checked elements
9400 //=======================================================================
9402 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9403 SMDS_ElemIteratorPtr theItr,
9404 const int theShapeID)
9407 SMESHDS_Mesh* meshDS = GetMeshDS();
9408 const bool notFromGroups = false;
9410 while( theItr->more() )
9412 const SMDS_MeshElement* elem = theItr->next();
9414 if( elem && elem->IsQuadratic())
9416 int id = elem->GetID();
9417 int nbNodes = elem->NbNodes();
9418 vector<const SMDS_MeshNode *> nodes, mediumNodes;
9419 nodes.reserve( nbNodes );
9420 mediumNodes.reserve( nbNodes );
9422 for(int i = 0; i < nbNodes; i++)
9424 const SMDS_MeshNode* n = elem->GetNode(i);
9426 if( elem->IsMediumNode( n ) )
9427 mediumNodes.push_back( n );
9429 nodes.push_back( n );
9431 if( nodes.empty() ) continue;
9432 SMDSAbs_ElementType aType = elem->GetType();
9434 //remove old quadratic element
9435 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9437 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9438 ReplaceElemInGroups(elem, NewElem, meshDS);
9439 if( theSm && NewElem )
9440 theSm->AddElement( NewElem );
9442 // remove medium nodes
9443 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9444 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9445 const SMDS_MeshNode* n = *nIt;
9446 if ( n->NbInverseElements() == 0 ) {
9447 if ( n->getshapeId() != theShapeID )
9448 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9449 ( n->getshapeId() ));
9451 meshDS->RemoveFreeNode( n, theSm );
9459 //=======================================================================
9460 //function : ConvertFromQuadratic
9462 //=======================================================================
9463 bool SMESH_MeshEditor::ConvertFromQuadratic()
9465 int nbCheckedElems = 0;
9466 if ( myMesh->HasShapeToMesh() )
9468 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9470 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9471 while ( smIt->more() ) {
9472 SMESH_subMesh* sm = smIt->next();
9473 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9474 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9480 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9481 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9483 SMESHDS_SubMesh *aSM = 0;
9484 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9490 //=======================================================================
9491 //function : SewSideElements
9493 //=======================================================================
9495 SMESH_MeshEditor::Sew_Error
9496 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9497 TIDSortedElemSet& theSide2,
9498 const SMDS_MeshNode* theFirstNode1,
9499 const SMDS_MeshNode* theFirstNode2,
9500 const SMDS_MeshNode* theSecondNode1,
9501 const SMDS_MeshNode* theSecondNode2)
9503 myLastCreatedElems.Clear();
9504 myLastCreatedNodes.Clear();
9506 MESSAGE ("::::SewSideElements()");
9507 if ( theSide1.size() != theSide2.size() )
9508 return SEW_DIFF_NB_OF_ELEMENTS;
9510 Sew_Error aResult = SEW_OK;
9512 // 1. Build set of faces representing each side
9513 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9514 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9516 // =======================================================================
9517 // 1. Build set of faces representing each side:
9518 // =======================================================================
9519 // a. build set of nodes belonging to faces
9520 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9521 // c. create temporary faces representing side of volumes if correspondent
9522 // face does not exist
9524 SMESHDS_Mesh* aMesh = GetMeshDS();
9525 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9526 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9527 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9528 set<const SMDS_MeshElement*> volSet1, volSet2;
9529 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9530 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9531 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9532 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9533 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9534 int iSide, iFace, iNode;
9536 list<const SMDS_MeshElement* > tempFaceList;
9537 for ( iSide = 0; iSide < 2; iSide++ ) {
9538 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9539 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9540 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9541 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9542 set<const SMDS_MeshElement*>::iterator vIt;
9543 TIDSortedElemSet::iterator eIt;
9544 set<const SMDS_MeshNode*>::iterator nIt;
9546 // check that given nodes belong to given elements
9547 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9548 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9549 int firstIndex = -1, secondIndex = -1;
9550 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9551 const SMDS_MeshElement* elem = *eIt;
9552 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9553 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9554 if ( firstIndex > -1 && secondIndex > -1 ) break;
9556 if ( firstIndex < 0 || secondIndex < 0 ) {
9557 // we can simply return until temporary faces created
9558 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9561 // -----------------------------------------------------------
9562 // 1a. Collect nodes of existing faces
9563 // and build set of face nodes in order to detect missing
9564 // faces corresponding to sides of volumes
9565 // -----------------------------------------------------------
9567 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9569 // loop on the given element of a side
9570 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9571 //const SMDS_MeshElement* elem = *eIt;
9572 const SMDS_MeshElement* elem = *eIt;
9573 if ( elem->GetType() == SMDSAbs_Face ) {
9574 faceSet->insert( elem );
9575 set <const SMDS_MeshNode*> faceNodeSet;
9576 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9577 while ( nodeIt->more() ) {
9578 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9579 nodeSet->insert( n );
9580 faceNodeSet.insert( n );
9582 setOfFaceNodeSet.insert( faceNodeSet );
9584 else if ( elem->GetType() == SMDSAbs_Volume )
9585 volSet->insert( elem );
9587 // ------------------------------------------------------------------------------
9588 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9589 // ------------------------------------------------------------------------------
9591 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9592 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9593 while ( fIt->more() ) { // loop on faces sharing a node
9594 const SMDS_MeshElement* f = fIt->next();
9595 if ( faceSet->find( f ) == faceSet->end() ) {
9596 // check if all nodes are in nodeSet and
9597 // complete setOfFaceNodeSet if they are
9598 set <const SMDS_MeshNode*> faceNodeSet;
9599 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9600 bool allInSet = true;
9601 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9602 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9603 if ( nodeSet->find( n ) == nodeSet->end() )
9606 faceNodeSet.insert( n );
9609 faceSet->insert( f );
9610 setOfFaceNodeSet.insert( faceNodeSet );
9616 // -------------------------------------------------------------------------
9617 // 1c. Create temporary faces representing sides of volumes if correspondent
9618 // face does not exist
9619 // -------------------------------------------------------------------------
9621 if ( !volSet->empty() ) {
9622 //int nodeSetSize = nodeSet->size();
9624 // loop on given volumes
9625 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9626 SMDS_VolumeTool vol (*vIt);
9627 // loop on volume faces: find free faces
9628 // --------------------------------------
9629 list<const SMDS_MeshElement* > freeFaceList;
9630 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9631 if ( !vol.IsFreeFace( iFace ))
9633 // check if there is already a face with same nodes in a face set
9634 const SMDS_MeshElement* aFreeFace = 0;
9635 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9636 int nbNodes = vol.NbFaceNodes( iFace );
9637 set <const SMDS_MeshNode*> faceNodeSet;
9638 vol.GetFaceNodes( iFace, faceNodeSet );
9639 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9641 // no such a face is given but it still can exist, check it
9642 if ( nbNodes == 3 ) {
9643 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9645 else if ( nbNodes == 4 ) {
9646 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9649 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9650 aFreeFace = aMesh->FindFace(poly_nodes);
9654 // create a temporary face
9655 if ( nbNodes == 3 ) {
9656 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9657 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9659 else if ( nbNodes == 4 ) {
9660 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9661 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9664 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9665 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9666 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9670 freeFaceList.push_back( aFreeFace );
9671 tempFaceList.push_back( aFreeFace );
9674 } // loop on faces of a volume
9676 // choose one of several free faces
9677 // --------------------------------------
9678 if ( freeFaceList.size() > 1 ) {
9679 // choose a face having max nb of nodes shared by other elems of a side
9680 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9681 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9682 while ( fIt != freeFaceList.end() ) { // loop on free faces
9683 int nbSharedNodes = 0;
9684 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9685 while ( nodeIt->more() ) { // loop on free face nodes
9686 const SMDS_MeshNode* n =
9687 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9688 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9689 while ( invElemIt->more() ) {
9690 const SMDS_MeshElement* e = invElemIt->next();
9691 if ( faceSet->find( e ) != faceSet->end() )
9693 if ( elemSet->find( e ) != elemSet->end() )
9697 if ( nbSharedNodes >= maxNbNodes ) {
9698 maxNbNodes = nbSharedNodes;
9702 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9704 if ( freeFaceList.size() > 1 )
9706 // could not choose one face, use another way
9707 // choose a face most close to the bary center of the opposite side
9708 gp_XYZ aBC( 0., 0., 0. );
9709 set <const SMDS_MeshNode*> addedNodes;
9710 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9711 eIt = elemSet2->begin();
9712 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9713 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9714 while ( nodeIt->more() ) { // loop on free face nodes
9715 const SMDS_MeshNode* n =
9716 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9717 if ( addedNodes.insert( n ).second )
9718 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9721 aBC /= addedNodes.size();
9722 double minDist = DBL_MAX;
9723 fIt = freeFaceList.begin();
9724 while ( fIt != freeFaceList.end() ) { // loop on free faces
9726 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9727 while ( nodeIt->more() ) { // loop on free face nodes
9728 const SMDS_MeshNode* n =
9729 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9730 gp_XYZ p( n->X(),n->Y(),n->Z() );
9731 dist += ( aBC - p ).SquareModulus();
9733 if ( dist < minDist ) {
9735 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9738 fIt = freeFaceList.erase( fIt++ );
9741 } // choose one of several free faces of a volume
9743 if ( freeFaceList.size() == 1 ) {
9744 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9745 faceSet->insert( aFreeFace );
9746 // complete a node set with nodes of a found free face
9747 // for ( iNode = 0; iNode < ; iNode++ )
9748 // nodeSet->insert( fNodes[ iNode ] );
9751 } // loop on volumes of a side
9753 // // complete a set of faces if new nodes in a nodeSet appeared
9754 // // ----------------------------------------------------------
9755 // if ( nodeSetSize != nodeSet->size() ) {
9756 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9757 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9758 // while ( fIt->more() ) { // loop on faces sharing a node
9759 // const SMDS_MeshElement* f = fIt->next();
9760 // if ( faceSet->find( f ) == faceSet->end() ) {
9761 // // check if all nodes are in nodeSet and
9762 // // complete setOfFaceNodeSet if they are
9763 // set <const SMDS_MeshNode*> faceNodeSet;
9764 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9765 // bool allInSet = true;
9766 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9767 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9768 // if ( nodeSet->find( n ) == nodeSet->end() )
9769 // allInSet = false;
9771 // faceNodeSet.insert( n );
9773 // if ( allInSet ) {
9774 // faceSet->insert( f );
9775 // setOfFaceNodeSet.insert( faceNodeSet );
9781 } // Create temporary faces, if there are volumes given
9784 if ( faceSet1.size() != faceSet2.size() ) {
9785 // delete temporary faces: they are in reverseElements of actual nodes
9786 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9787 // while ( tmpFaceIt->more() )
9788 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9789 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9790 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9791 // aMesh->RemoveElement(*tmpFaceIt);
9792 MESSAGE("Diff nb of faces");
9793 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9796 // ============================================================
9797 // 2. Find nodes to merge:
9798 // bind a node to remove to a node to put instead
9799 // ============================================================
9801 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9802 if ( theFirstNode1 != theFirstNode2 )
9803 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9804 if ( theSecondNode1 != theSecondNode2 )
9805 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9807 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9808 set< long > linkIdSet; // links to process
9809 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9811 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9812 list< NLink > linkList[2];
9813 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9814 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9815 // loop on links in linkList; find faces by links and append links
9816 // of the found faces to linkList
9817 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9818 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9819 NLink link[] = { *linkIt[0], *linkIt[1] };
9820 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9821 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9824 // by links, find faces in the face sets,
9825 // and find indices of link nodes in the found faces;
9826 // in a face set, there is only one or no face sharing a link
9827 // ---------------------------------------------------------------
9829 const SMDS_MeshElement* face[] = { 0, 0 };
9830 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9831 vector<const SMDS_MeshNode*> fnodes1(9);
9832 vector<const SMDS_MeshNode*> fnodes2(9);
9833 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9834 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9835 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9836 int iLinkNode[2][2];
9837 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9838 const SMDS_MeshNode* n1 = link[iSide].first;
9839 const SMDS_MeshNode* n2 = link[iSide].second;
9840 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9841 set< const SMDS_MeshElement* > fMap;
9842 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9843 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9844 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9845 while ( fIt->more() ) { // loop on faces sharing a node
9846 const SMDS_MeshElement* f = fIt->next();
9847 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9848 ! fMap.insert( f ).second ) // f encounters twice
9850 if ( face[ iSide ] ) {
9851 MESSAGE( "2 faces per link " );
9852 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9856 faceSet->erase( f );
9857 // get face nodes and find ones of a link
9862 fnodes1.resize(f->NbNodes()+1);
9863 notLinkNodes1.resize(f->NbNodes()-2);
9866 fnodes2.resize(f->NbNodes()+1);
9867 notLinkNodes2.resize(f->NbNodes()-2);
9870 if(!f->IsQuadratic()) {
9871 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9872 while ( nIt->more() ) {
9873 const SMDS_MeshNode* n =
9874 static_cast<const SMDS_MeshNode*>( nIt->next() );
9876 iLinkNode[ iSide ][ 0 ] = iNode;
9878 else if ( n == n2 ) {
9879 iLinkNode[ iSide ][ 1 ] = iNode;
9881 //else if ( notLinkNodes[ iSide ][ 0 ] )
9882 // notLinkNodes[ iSide ][ 1 ] = n;
9884 // notLinkNodes[ iSide ][ 0 ] = n;
9888 notLinkNodes1[nbl] = n;
9889 //notLinkNodes1.push_back(n);
9891 notLinkNodes2[nbl] = n;
9892 //notLinkNodes2.push_back(n);
9894 //faceNodes[ iSide ][ iNode++ ] = n;
9896 fnodes1[iNode++] = n;
9899 fnodes2[iNode++] = n;
9903 else { // f->IsQuadratic()
9904 const SMDS_VtkFace* F =
9905 dynamic_cast<const SMDS_VtkFace*>(f);
9906 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9907 // use special nodes iterator
9908 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9909 while ( anIter->more() ) {
9910 const SMDS_MeshNode* n =
9911 static_cast<const SMDS_MeshNode*>( anIter->next() );
9913 iLinkNode[ iSide ][ 0 ] = iNode;
9915 else if ( n == n2 ) {
9916 iLinkNode[ iSide ][ 1 ] = iNode;
9921 notLinkNodes1[nbl] = n;
9924 notLinkNodes2[nbl] = n;
9928 fnodes1[iNode++] = n;
9931 fnodes2[iNode++] = n;
9935 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9937 fnodes1[iNode] = fnodes1[0];
9940 fnodes2[iNode] = fnodes1[0];
9947 // check similarity of elements of the sides
9948 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9949 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9950 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9951 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9954 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9956 break; // do not return because it s necessary to remove tmp faces
9959 // set nodes to merge
9960 // -------------------
9962 if ( face[0] && face[1] ) {
9963 int nbNodes = face[0]->NbNodes();
9964 if ( nbNodes != face[1]->NbNodes() ) {
9965 MESSAGE("Diff nb of face nodes");
9966 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9967 break; // do not return because it s necessary to remove tmp faces
9969 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9970 if ( nbNodes == 3 ) {
9971 //nReplaceMap.insert( TNodeNodeMap::value_type
9972 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9973 nReplaceMap.insert( TNodeNodeMap::value_type
9974 ( notLinkNodes1[0], notLinkNodes2[0] ));
9977 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9978 // analyse link orientation in faces
9979 int i1 = iLinkNode[ iSide ][ 0 ];
9980 int i2 = iLinkNode[ iSide ][ 1 ];
9981 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9982 // if notLinkNodes are the first and the last ones, then
9983 // their order does not correspond to the link orientation
9984 if (( i1 == 1 && i2 == 2 ) ||
9985 ( i1 == 2 && i2 == 1 ))
9986 reverse[ iSide ] = !reverse[ iSide ];
9988 if ( reverse[0] == reverse[1] ) {
9989 //nReplaceMap.insert( TNodeNodeMap::value_type
9990 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9991 //nReplaceMap.insert( TNodeNodeMap::value_type
9992 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9993 for(int nn=0; nn<nbNodes-2; nn++) {
9994 nReplaceMap.insert( TNodeNodeMap::value_type
9995 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9999 //nReplaceMap.insert( TNodeNodeMap::value_type
10000 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10001 //nReplaceMap.insert( TNodeNodeMap::value_type
10002 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10003 for(int nn=0; nn<nbNodes-2; nn++) {
10004 nReplaceMap.insert( TNodeNodeMap::value_type
10005 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10010 // add other links of the faces to linkList
10011 // -----------------------------------------
10013 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10014 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10015 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10016 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10017 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10018 if ( !iter_isnew.second ) { // already in a set: no need to process
10019 linkIdSet.erase( iter_isnew.first );
10021 else // new in set == encountered for the first time: add
10023 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10024 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10025 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10026 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10027 linkList[0].push_back ( NLink( n1, n2 ));
10028 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10032 } // loop on link lists
10034 if ( aResult == SEW_OK &&
10035 ( linkIt[0] != linkList[0].end() ||
10036 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10037 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10038 " " << (faceSetPtr[1]->empty()));
10039 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10042 // ====================================================================
10043 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10044 // ====================================================================
10046 // delete temporary faces: they are in reverseElements of actual nodes
10047 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10048 // while ( tmpFaceIt->more() )
10049 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10050 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10051 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10052 // aMesh->RemoveElement(*tmpFaceIt);
10054 if ( aResult != SEW_OK)
10057 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10058 // loop on nodes replacement map
10059 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10060 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10061 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10062 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10063 nodeIDsToRemove.push_back( nToRemove->GetID() );
10064 // loop on elements sharing nToRemove
10065 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10066 while ( invElemIt->more() ) {
10067 const SMDS_MeshElement* e = invElemIt->next();
10068 // get a new suite of nodes: make replacement
10069 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10070 vector< const SMDS_MeshNode*> nodes( nbNodes );
10071 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10072 while ( nIt->more() ) {
10073 const SMDS_MeshNode* n =
10074 static_cast<const SMDS_MeshNode*>( nIt->next() );
10075 nnIt = nReplaceMap.find( n );
10076 if ( nnIt != nReplaceMap.end() ) {
10078 n = (*nnIt).second;
10082 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10083 // elemIDsToRemove.push_back( e->GetID() );
10087 SMDSAbs_ElementType etyp = e->GetType();
10088 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10091 myLastCreatedElems.Append(newElem);
10092 AddToSameGroups(newElem, e, aMesh);
10093 int aShapeId = e->getshapeId();
10096 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10099 aMesh->RemoveElement(e);
10104 Remove( nodeIDsToRemove, true );
10109 //================================================================================
10111 * \brief Find corresponding nodes in two sets of faces
10112 * \param theSide1 - first face set
10113 * \param theSide2 - second first face
10114 * \param theFirstNode1 - a boundary node of set 1
10115 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10116 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10117 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10118 * \param nReplaceMap - output map of corresponding nodes
10119 * \retval bool - is a success or not
10121 //================================================================================
10124 //#define DEBUG_MATCHING_NODES
10127 SMESH_MeshEditor::Sew_Error
10128 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10129 set<const SMDS_MeshElement*>& theSide2,
10130 const SMDS_MeshNode* theFirstNode1,
10131 const SMDS_MeshNode* theFirstNode2,
10132 const SMDS_MeshNode* theSecondNode1,
10133 const SMDS_MeshNode* theSecondNode2,
10134 TNodeNodeMap & nReplaceMap)
10136 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10138 nReplaceMap.clear();
10139 if ( theFirstNode1 != theFirstNode2 )
10140 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10141 if ( theSecondNode1 != theSecondNode2 )
10142 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10144 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10145 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10147 list< NLink > linkList[2];
10148 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10149 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10151 // loop on links in linkList; find faces by links and append links
10152 // of the found faces to linkList
10153 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10154 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10155 NLink link[] = { *linkIt[0], *linkIt[1] };
10156 if ( linkSet.find( link[0] ) == linkSet.end() )
10159 // by links, find faces in the face sets,
10160 // and find indices of link nodes in the found faces;
10161 // in a face set, there is only one or no face sharing a link
10162 // ---------------------------------------------------------------
10164 const SMDS_MeshElement* face[] = { 0, 0 };
10165 list<const SMDS_MeshNode*> notLinkNodes[2];
10166 //bool reverse[] = { false, false }; // order of notLinkNodes
10168 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10170 const SMDS_MeshNode* n1 = link[iSide].first;
10171 const SMDS_MeshNode* n2 = link[iSide].second;
10172 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10173 set< const SMDS_MeshElement* > facesOfNode1;
10174 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10176 // during a loop of the first node, we find all faces around n1,
10177 // during a loop of the second node, we find one face sharing both n1 and n2
10178 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10179 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10180 while ( fIt->more() ) { // loop on faces sharing a node
10181 const SMDS_MeshElement* f = fIt->next();
10182 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10183 ! facesOfNode1.insert( f ).second ) // f encounters twice
10185 if ( face[ iSide ] ) {
10186 MESSAGE( "2 faces per link " );
10187 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10190 faceSet->erase( f );
10192 // get not link nodes
10193 int nbN = f->NbNodes();
10194 if ( f->IsQuadratic() )
10196 nbNodes[ iSide ] = nbN;
10197 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10198 int i1 = f->GetNodeIndex( n1 );
10199 int i2 = f->GetNodeIndex( n2 );
10200 int iEnd = nbN, iBeg = -1, iDelta = 1;
10201 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10203 std::swap( iEnd, iBeg ); iDelta = -1;
10208 if ( i == iEnd ) i = iBeg + iDelta;
10209 if ( i == i1 ) break;
10210 nodes.push_back ( f->GetNode( i ) );
10216 // check similarity of elements of the sides
10217 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10218 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10219 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10220 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10223 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10227 // set nodes to merge
10228 // -------------------
10230 if ( face[0] && face[1] ) {
10231 if ( nbNodes[0] != nbNodes[1] ) {
10232 MESSAGE("Diff nb of face nodes");
10233 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10235 #ifdef DEBUG_MATCHING_NODES
10236 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10237 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10238 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10240 int nbN = nbNodes[0];
10242 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10243 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10244 for ( int i = 0 ; i < nbN - 2; ++i ) {
10245 #ifdef DEBUG_MATCHING_NODES
10246 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10248 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10252 // add other links of the face 1 to linkList
10253 // -----------------------------------------
10255 const SMDS_MeshElement* f0 = face[0];
10256 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10257 for ( int i = 0; i < nbN; i++ )
10259 const SMDS_MeshNode* n2 = f0->GetNode( i );
10260 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10261 linkSet.insert( SMESH_TLink( n1, n2 ));
10262 if ( !iter_isnew.second ) { // already in a set: no need to process
10263 linkSet.erase( iter_isnew.first );
10265 else // new in set == encountered for the first time: add
10267 #ifdef DEBUG_MATCHING_NODES
10268 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10269 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10271 linkList[0].push_back ( NLink( n1, n2 ));
10272 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10277 } // loop on link lists
10282 //================================================================================
10284 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10285 \param theElems - the list of elements (edges or faces) to be replicated
10286 The nodes for duplication could be found from these elements
10287 \param theNodesNot - list of nodes to NOT replicate
10288 \param theAffectedElems - the list of elements (cells and edges) to which the
10289 replicated nodes should be associated to.
10290 \return TRUE if operation has been completed successfully, FALSE otherwise
10292 //================================================================================
10294 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10295 const TIDSortedElemSet& theNodesNot,
10296 const TIDSortedElemSet& theAffectedElems )
10298 myLastCreatedElems.Clear();
10299 myLastCreatedNodes.Clear();
10301 if ( theElems.size() == 0 )
10304 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10309 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10310 // duplicate elements and nodes
10311 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10312 // replce nodes by duplications
10313 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10317 //================================================================================
10319 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10320 \param theMeshDS - mesh instance
10321 \param theElems - the elements replicated or modified (nodes should be changed)
10322 \param theNodesNot - nodes to NOT replicate
10323 \param theNodeNodeMap - relation of old node to new created node
10324 \param theIsDoubleElem - flag os to replicate element or modify
10325 \return TRUE if operation has been completed successfully, FALSE otherwise
10327 //================================================================================
10329 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10330 const TIDSortedElemSet& theElems,
10331 const TIDSortedElemSet& theNodesNot,
10332 std::map< const SMDS_MeshNode*,
10333 const SMDS_MeshNode* >& theNodeNodeMap,
10334 const bool theIsDoubleElem )
10336 MESSAGE("doubleNodes");
10337 // iterate on through element and duplicate them (by nodes duplication)
10339 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10340 for ( ; elemItr != theElems.end(); ++elemItr )
10342 const SMDS_MeshElement* anElem = *elemItr;
10346 bool isDuplicate = false;
10347 // duplicate nodes to duplicate element
10348 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10349 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10351 while ( anIter->more() )
10354 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10355 SMDS_MeshNode* aNewNode = aCurrNode;
10356 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10357 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10358 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10361 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10362 theNodeNodeMap[ aCurrNode ] = aNewNode;
10363 myLastCreatedNodes.Append( aNewNode );
10365 isDuplicate |= (aCurrNode != aNewNode);
10366 newNodes[ ind++ ] = aNewNode;
10368 if ( !isDuplicate )
10371 if ( theIsDoubleElem )
10372 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10375 MESSAGE("ChangeElementNodes");
10376 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10383 //================================================================================
10385 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10386 \param theNodes - identifiers of nodes to be doubled
10387 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10388 nodes. If list of element identifiers is empty then nodes are doubled but
10389 they not assigned to elements
10390 \return TRUE if operation has been completed successfully, FALSE otherwise
10392 //================================================================================
10394 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10395 const std::list< int >& theListOfModifiedElems )
10397 MESSAGE("DoubleNodes");
10398 myLastCreatedElems.Clear();
10399 myLastCreatedNodes.Clear();
10401 if ( theListOfNodes.size() == 0 )
10404 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10408 // iterate through nodes and duplicate them
10410 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10412 std::list< int >::const_iterator aNodeIter;
10413 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10415 int aCurr = *aNodeIter;
10416 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10422 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10425 anOldNodeToNewNode[ aNode ] = aNewNode;
10426 myLastCreatedNodes.Append( aNewNode );
10430 // Create map of new nodes for modified elements
10432 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10434 std::list< int >::const_iterator anElemIter;
10435 for ( anElemIter = theListOfModifiedElems.begin();
10436 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10438 int aCurr = *anElemIter;
10439 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10443 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10445 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10447 while ( anIter->more() )
10449 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10450 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10452 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10453 aNodeArr[ ind++ ] = aNewNode;
10456 aNodeArr[ ind++ ] = aCurrNode;
10458 anElemToNodes[ anElem ] = aNodeArr;
10461 // Change nodes of elements
10463 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10464 anElemToNodesIter = anElemToNodes.begin();
10465 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10467 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10468 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10471 MESSAGE("ChangeElementNodes");
10472 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10481 //================================================================================
10483 \brief Check if element located inside shape
10484 \return TRUE if IN or ON shape, FALSE otherwise
10486 //================================================================================
10488 template<class Classifier>
10489 bool isInside(const SMDS_MeshElement* theElem,
10490 Classifier& theClassifier,
10491 const double theTol)
10493 gp_XYZ centerXYZ (0, 0, 0);
10494 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10495 while (aNodeItr->more())
10496 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10498 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10499 theClassifier.Perform(aPnt, theTol);
10500 TopAbs_State aState = theClassifier.State();
10501 return (aState == TopAbs_IN || aState == TopAbs_ON );
10504 //================================================================================
10506 * \brief Classifier of the 3D point on the TopoDS_Face
10507 * with interaface suitable for isInside()
10509 //================================================================================
10511 struct _FaceClassifier
10513 Extrema_ExtPS _extremum;
10514 BRepAdaptor_Surface _surface;
10515 TopAbs_State _state;
10517 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10519 _extremum.Initialize( _surface,
10520 _surface.FirstUParameter(), _surface.LastUParameter(),
10521 _surface.FirstVParameter(), _surface.LastVParameter(),
10522 _surface.Tolerance(), _surface.Tolerance() );
10524 void Perform(const gp_Pnt& aPnt, double theTol)
10526 _state = TopAbs_OUT;
10527 _extremum.Perform(aPnt);
10528 if ( _extremum.IsDone() )
10529 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10530 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10532 TopAbs_State State() const
10539 //================================================================================
10541 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10542 \param theElems - group of of elements (edges or faces) to be replicated
10543 \param theNodesNot - group of nodes not to replicate
10544 \param theShape - shape to detect affected elements (element which geometric center
10545 located on or inside shape).
10546 The replicated nodes should be associated to affected elements.
10547 \return TRUE if operation has been completed successfully, FALSE otherwise
10549 //================================================================================
10551 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10552 const TIDSortedElemSet& theNodesNot,
10553 const TopoDS_Shape& theShape )
10555 if ( theShape.IsNull() )
10558 const double aTol = Precision::Confusion();
10559 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10560 auto_ptr<_FaceClassifier> aFaceClassifier;
10561 if ( theShape.ShapeType() == TopAbs_SOLID )
10563 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10564 bsc3d->PerformInfinitePoint(aTol);
10566 else if (theShape.ShapeType() == TopAbs_FACE )
10568 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10571 // iterates on indicated elements and get elements by back references from their nodes
10572 TIDSortedElemSet anAffected;
10573 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10574 for ( ; elemItr != theElems.end(); ++elemItr )
10576 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10580 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10581 while ( nodeItr->more() )
10583 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10584 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10586 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10587 while ( backElemItr->more() )
10589 const SMDS_MeshElement* curElem = backElemItr->next();
10590 if ( curElem && theElems.find(curElem) == theElems.end() &&
10592 isInside( curElem, *bsc3d, aTol ) :
10593 isInside( curElem, *aFaceClassifier, aTol )))
10594 anAffected.insert( curElem );
10598 return DoubleNodes( theElems, theNodesNot, anAffected );
10602 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10603 * The list of groups must describe a partition of the mesh volumes.
10604 * The nodes of the internal faces at the boundaries of the groups are doubled.
10605 * In option, the internal faces are replaced by flat elements.
10606 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10607 * @param theElems - list of groups of volumes, where a group of volume is a set of
10608 * SMDS_MeshElements sorted by Id.
10609 * @param createJointElems - if TRUE, create the elements
10610 * @return TRUE if operation has been completed successfully, FALSE otherwise
10612 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10613 bool createJointElems)
10615 MESSAGE("------------------------------------------------------");
10616 MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10617 MESSAGE("------------------------------------------------------");
10619 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10620 meshDS->BuildDownWardConnectivity(false);
10622 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10624 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10625 // build the list of nodes shared by 2 or more domains, with their domain indexes
10627 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10628 std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
10629 faceDomains.clear();
10630 nodeDomains.clear();
10631 std::map<int,int> emptyMap;
10634 for (int idom = 0; idom < theElems.size(); idom++)
10637 // --- build a map (face to duplicate --> volume to modify)
10638 // with all the faces shared by 2 domains (group of elements)
10639 // and corresponding volume of this domain, for each shared face.
10640 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10642 const TIDSortedElemSet& domain = theElems[idom];
10643 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10644 for (; elemItr != domain.end(); ++elemItr)
10646 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10649 int vtkId = anElem->getVtkId();
10650 int neighborsVtkIds[NBMAXNEIGHBORS];
10651 int downIds[NBMAXNEIGHBORS];
10652 unsigned char downTypes[NBMAXNEIGHBORS];
10653 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10654 for (int n = 0; n < nbNeighbors; n++)
10656 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10657 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10658 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10660 DownIdType face(downIds[n], downTypes[n]);
10661 if (!faceDomains.count(face))
10662 faceDomains[face] = emptyMap; // create an empty entry for face
10663 if (!faceDomains[face].count(idom))
10665 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10672 MESSAGE("Number of shared faces " << faceDomains.size());
10674 // --- for each shared face, get the nodes
10675 // for each node, for each domain of the face, create a clone of the node
10677 std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10678 for( ; itface != faceDomains.end();++itface )
10680 DownIdType face = itface->first;
10681 std::map<int,int> domvol = itface->second;
10682 std::set<int> oldNodes;
10684 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10685 std::set<int>::iterator itn = oldNodes.begin();
10686 for (;itn != oldNodes.end(); ++itn)
10689 if (!nodeDomains.count(oldId))
10690 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10691 std::map<int,int>::iterator itdom = domvol.begin();
10692 for(; itdom != domvol.end(); ++itdom)
10694 int idom = itdom->first;
10695 if ( nodeDomains[oldId].empty() )
10696 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10699 double *coords = grid->GetPoint(oldId);
10700 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10701 int newId = newNode->getVtkId();
10702 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10708 // --- iterate on shared faces (volumes to modify, face to extrude)
10709 // get node id's of the face (id SMDS = id VTK)
10710 // create flat element with old and new nodes if requested
10712 if (createJointElems)
10714 itface = faceDomains.begin();
10715 for( ; itface != faceDomains.end();++itface )
10717 DownIdType face = itface->first;
10718 std::set<int> oldNodes;
10719 std::set<int>::iterator itn;
10721 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10722 std::map<int,int> localClonedNodeIds;
10724 std::map<int,int> domvol = itface->second;
10725 std::map<int,int>::iterator itdom = domvol.begin();
10726 int dom1 = itdom->first;
10727 int vtkVolId = itdom->second;
10729 int dom2 = itdom->first;
10731 localClonedNodeIds.clear();
10732 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10736 if (nodeDomains[oldId].count(dom1))
10737 refid = nodeDomains[oldId][dom1];
10739 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10741 if (nodeDomains[oldId].count(dom2))
10742 newid = nodeDomains[oldId][dom2];
10744 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10745 localClonedNodeIds[oldId] = newid;
10747 meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10751 // --- iterate on shared faces (volumes to modify, face to extrude)
10752 // get node id's of the face
10753 // replace old nodes by new nodes in volumes, and update inverse connectivity
10755 itface = faceDomains.begin();
10756 for( ; itface != faceDomains.end();++itface )
10758 DownIdType face = itface->first;
10759 std::set<int> oldNodes;
10760 std::set<int>::iterator itn;
10762 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10763 std::map<int,int> localClonedNodeIds;
10765 std::map<int,int> domvol = itface->second;
10766 std::map<int,int>::iterator itdom = domvol.begin();
10767 for(; itdom != domvol.end(); ++itdom)
10769 int idom = itdom->first;
10770 int vtkVolId = itdom->second;
10771 localClonedNodeIds.clear();
10772 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10775 if (nodeDomains[oldId].count(idom))
10776 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10778 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10781 grid->BuildLinks();
10783 // TODO replace also old nodes by new nodes in faces and edges
10789 //================================================================================
10791 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10792 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10793 * \return TRUE if operation has been completed successfully, FALSE otherwise
10795 //================================================================================
10797 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10799 // iterates on volume elements and detect all free faces on them
10800 SMESHDS_Mesh* aMesh = GetMeshDS();
10803 //bool res = false;
10804 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10805 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10808 const SMDS_MeshVolume* volume = vIt->next();
10809 SMDS_VolumeTool vTool( volume );
10810 vTool.SetExternalNormal();
10811 const bool isPoly = volume->IsPoly();
10812 const bool isQuad = volume->IsQuadratic();
10813 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10815 if (!vTool.IsFreeFace(iface))
10818 vector<const SMDS_MeshNode *> nodes;
10819 int nbFaceNodes = vTool.NbFaceNodes(iface);
10820 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10822 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10823 nodes.push_back(faceNodes[inode]);
10825 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10826 nodes.push_back(faceNodes[inode]);
10828 // add new face based on volume nodes
10829 if (aMesh->FindFace( nodes ) ) {
10831 continue; // face already exsist
10833 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10837 return ( nbFree==(nbExisted+nbCreated) );
10842 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10844 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10846 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10849 //================================================================================
10851 * \brief Creates missing boundary elements
10852 * \param elements - elements whose boundary is to be checked
10853 * \param dimension - defines type of boundary elements to create
10854 * \param group - a group to store created boundary elements in
10855 * \param targetMesh - a mesh to store created boundary elements in
10856 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10857 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10858 * boundary elements will be copied into the targetMesh
10860 //================================================================================
10862 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10863 Bnd_Dimension dimension,
10864 SMESH_Group* group/*=0*/,
10865 SMESH_Mesh* targetMesh/*=0*/,
10866 bool toCopyElements/*=false*/,
10867 bool toCopyExistingBondary/*=false*/)
10869 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10870 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10871 // hope that all elements are of the same type, do not check them all
10872 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10873 throw SALOME_Exception(LOCALIZED("wrong element type"));
10876 toCopyElements = toCopyExistingBondary = false;
10878 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10879 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10881 SMDS_VolumeTool vTool;
10882 TIDSortedElemSet emptySet, avoidSet;
10885 typedef vector<const SMDS_MeshNode*> TConnectivity;
10887 SMDS_ElemIteratorPtr eIt;
10888 if (elements.empty())
10889 eIt = aMesh->elementsIterator(elemType);
10891 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10893 while (eIt->more())
10895 const SMDS_MeshElement* elem = eIt->next();
10896 const int iQuad = elem->IsQuadratic();
10898 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10899 vector<const SMDS_MeshElement*> presentBndElems;
10900 vector<TConnectivity> missingBndElems;
10901 TConnectivity nodes;
10902 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10904 vTool.SetExternalNormal();
10905 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10907 if (!vTool.IsFreeFace(iface))
10909 int nbFaceNodes = vTool.NbFaceNodes(iface);
10910 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10911 if ( missType == SMDSAbs_Edge ) // boundary edges
10913 nodes.resize( 2+iQuad );
10914 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10916 for ( int j = 0; j < nodes.size(); ++j )
10918 if ( const SMDS_MeshElement* edge =
10919 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10920 presentBndElems.push_back( edge );
10922 missingBndElems.push_back( nodes );
10925 else // boundary face
10928 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10929 nodes.push_back( nn[inode] );
10931 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10932 nodes.push_back( nn[inode] );
10934 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10935 presentBndElems.push_back( f );
10937 missingBndElems.push_back( nodes );
10941 else // elem is a face ------------------------------------------
10943 avoidSet.clear(), avoidSet.insert( elem );
10944 int nbNodes = elem->NbCornerNodes();
10945 nodes.resize( 2 /*+ iQuad*/);
10946 for ( int i = 0; i < nbNodes; i++ )
10948 nodes[0] = elem->GetNode(i);
10949 nodes[1] = elem->GetNode((i+1)%nbNodes);
10950 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10951 continue; // not free link
10954 //nodes[2] = elem->GetNode( i + nbNodes );
10955 if ( const SMDS_MeshElement* edge =
10956 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10957 presentBndElems.push_back( edge );
10959 missingBndElems.push_back( nodes );
10963 // 2. Add missing boundary elements
10964 if ( targetMesh != myMesh )
10965 // instead of making a map of nodes in this mesh and targetMesh,
10966 // we create nodes with same IDs. We can renumber them later, if needed
10967 for ( int i = 0; i < missingBndElems.size(); ++i )
10969 TConnectivity& srcNodes = missingBndElems[i];
10970 TConnectivity nodes( srcNodes.size() );
10971 for ( inode = 0; inode < nodes.size(); ++inode )
10972 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10973 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10976 for ( int i = 0; i < missingBndElems.size(); ++i )
10978 TConnectivity& nodes = missingBndElems[i];
10979 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10982 // 3. Copy present boundary elements
10983 if ( toCopyExistingBondary )
10984 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10986 const SMDS_MeshElement* e = presentBndElems[i];
10987 TConnectivity nodes( e->NbNodes() );
10988 for ( inode = 0; inode < nodes.size(); ++inode )
10989 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10990 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10991 // leave only missing elements in tgtEditor.myLastCreatedElems
10992 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10994 } // loop on given elements
10996 // 4. Fill group with missing boundary elements
10999 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11000 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11001 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11003 tgtEditor.myLastCreatedElems.Clear();
11005 // 5. Copy given elements
11006 if ( toCopyElements )
11008 if (elements.empty())
11009 eIt = aMesh->elementsIterator(elemType);
11011 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11012 while (eIt->more())
11014 const SMDS_MeshElement* elem = eIt->next();
11015 TConnectivity nodes( elem->NbNodes() );
11016 for ( inode = 0; inode < nodes.size(); ++inode )
11017 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11018 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11020 tgtEditor.myLastCreatedElems.Clear();