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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) e = mesh->AddPolygonalFaceWithID(node, ID);
159 else e = mesh->AddPolygonalFace (node );
166 if ( ID >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) 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 >= 0 ) e = mesh->Add0DElementWithID(node[0], ID);
244 else e = mesh->Add0DElement (node[0] );
249 if ( ID >= 0 ) 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, 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, 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 = 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 ElementBndBoxTree* _ebbTree;
6481 SMESH_NodeSearcherImpl* _nodeSearcher;
6482 SMDSAbs_ElementType _elementType;
6484 bool _outerFacesFound;
6485 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6487 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6488 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6489 ~SMESH_ElementSearcherImpl()
6491 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6492 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6494 virtual int FindElementsByPoint(const gp_Pnt& point,
6495 SMDSAbs_ElementType type,
6496 vector< const SMDS_MeshElement* >& foundElements);
6497 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6499 void GetElementsNearLine( const gp_Ax1& line,
6500 SMDSAbs_ElementType type,
6501 vector< const SMDS_MeshElement* >& foundElems);
6502 double getTolerance();
6503 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6504 const double tolerance, double & param);
6505 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6506 bool isOuterBoundary(const SMDS_MeshElement* face) const
6508 return _outerFaces.empty() || _outerFaces.count(face);
6510 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6512 const SMDS_MeshElement* _face;
6514 bool _coincides; //!< the line lays in face plane
6515 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6516 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6518 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6521 TIDSortedElemSet _faces;
6522 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6523 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6527 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6529 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6530 << ", _coincides="<<i._coincides << ")";
6533 //=======================================================================
6535 * \brief define tolerance for search
6537 //=======================================================================
6539 double SMESH_ElementSearcherImpl::getTolerance()
6541 if ( _tolerance < 0 )
6543 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6546 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6548 double boxSize = _nodeSearcher->getTree()->maxSize();
6549 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6551 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6553 double boxSize = _ebbTree->maxSize();
6554 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6556 if ( _tolerance == 0 )
6558 // define tolerance by size of a most complex element
6559 int complexType = SMDSAbs_Volume;
6560 while ( complexType > SMDSAbs_All &&
6561 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6563 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6565 if ( complexType == int( SMDSAbs_Node ))
6567 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6569 if ( meshInfo.NbNodes() > 2 )
6570 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6574 SMDS_ElemIteratorPtr elemIt =
6575 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6576 const SMDS_MeshElement* elem = elemIt->next();
6577 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6578 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6579 while ( nodeIt->more() )
6581 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6582 elemSize = max( dist, elemSize );
6585 _tolerance = 1e-4 * elemSize;
6591 //================================================================================
6593 * \brief Find intersection of the line and an edge of face and return parameter on line
6595 //================================================================================
6597 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6598 const SMDS_MeshElement* face,
6605 GeomAPI_ExtremaCurveCurve anExtCC;
6606 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6608 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6609 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6611 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6612 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6613 anExtCC.Init( lineCurve, edge);
6614 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6616 Quantity_Parameter pl, pe;
6617 anExtCC.LowerDistanceParameters( pl, pe );
6619 if ( ++nbInts == 2 )
6623 if ( nbInts > 0 ) param /= nbInts;
6626 //================================================================================
6628 * \brief Find all faces belonging to the outer boundary of mesh
6630 //================================================================================
6632 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6634 if ( _outerFacesFound ) return;
6636 // Collect all outer faces by passing from one outer face to another via their links
6637 // and BTW find out if there are internal faces at all.
6639 // checked links and links where outer boundary meets internal one
6640 set< SMESH_TLink > visitedLinks, seamLinks;
6642 // links to treat with already visited faces sharing them
6643 list < TFaceLink > startLinks;
6645 // load startLinks with the first outerFace
6646 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6647 _outerFaces.insert( outerFace );
6649 TIDSortedElemSet emptySet;
6650 while ( !startLinks.empty() )
6652 const SMESH_TLink& link = startLinks.front()._link;
6653 TIDSortedElemSet& faces = startLinks.front()._faces;
6655 outerFace = *faces.begin();
6656 // find other faces sharing the link
6657 const SMDS_MeshElement* f;
6658 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6661 // select another outer face among the found
6662 const SMDS_MeshElement* outerFace2 = 0;
6663 if ( faces.size() == 2 )
6665 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6667 else if ( faces.size() > 2 )
6669 seamLinks.insert( link );
6671 // link direction within the outerFace
6672 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6673 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6674 int i1 = outerFace->GetNodeIndex( link.node1() );
6675 int i2 = outerFace->GetNodeIndex( link.node2() );
6676 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6677 if ( rev ) n1n2.Reverse();
6679 gp_XYZ ofNorm, fNorm;
6680 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6682 // direction from the link inside outerFace
6683 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6684 // sort all other faces by angle with the dirInOF
6685 map< double, const SMDS_MeshElement* > angle2Face;
6686 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6687 for ( ; face != faces.end(); ++face )
6689 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6691 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6692 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6693 if ( angle < 0 ) angle += 2*PI;
6694 angle2Face.insert( make_pair( angle, *face ));
6696 if ( !angle2Face.empty() )
6697 outerFace2 = angle2Face.begin()->second;
6700 // store the found outer face and add its links to continue seaching from
6703 _outerFaces.insert( outerFace );
6704 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6705 for ( int i = 0; i < nbNodes; ++i )
6707 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6708 if ( visitedLinks.insert( link2 ).second )
6709 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6712 startLinks.pop_front();
6714 _outerFacesFound = true;
6716 if ( !seamLinks.empty() )
6718 // There are internal boundaries touching the outher one,
6719 // find all faces of internal boundaries in order to find
6720 // faces of boundaries of holes, if any.
6725 _outerFaces.clear();
6729 //=======================================================================
6731 * \brief Find elements of given type where the given point is IN or ON.
6732 * Returns nb of found elements and elements them-selves.
6734 * 'ALL' type means elements of any type excluding nodes and 0D elements
6736 //=======================================================================
6738 int SMESH_ElementSearcherImpl::
6739 FindElementsByPoint(const gp_Pnt& point,
6740 SMDSAbs_ElementType type,
6741 vector< const SMDS_MeshElement* >& foundElements)
6743 foundElements.clear();
6745 double tolerance = getTolerance();
6747 // =================================================================================
6748 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6750 if ( !_nodeSearcher )
6751 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6753 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6754 if ( !closeNode ) return foundElements.size();
6756 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6757 return foundElements.size(); // to far from any node
6759 if ( type == SMDSAbs_Node )
6761 foundElements.push_back( closeNode );
6765 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6766 while ( elemIt->more() )
6767 foundElements.push_back( elemIt->next() );
6770 // =================================================================================
6771 else // elements more complex than 0D
6773 if ( !_ebbTree || _elementType != type )
6775 if ( _ebbTree ) delete _ebbTree;
6776 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6778 TIDSortedElemSet suspectElems;
6779 _ebbTree->getElementsNearPoint( point, suspectElems );
6780 TIDSortedElemSet::iterator elem = suspectElems.begin();
6781 for ( ; elem != suspectElems.end(); ++elem )
6782 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6783 foundElements.push_back( *elem );
6785 return foundElements.size();
6788 //================================================================================
6790 * \brief Classify the given point in the closed 2D mesh
6792 //================================================================================
6794 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6796 double tolerance = getTolerance();
6797 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6799 if ( _ebbTree ) delete _ebbTree;
6800 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6802 // Algo: analyse transition of a line starting at the point through mesh boundary;
6803 // try three lines parallel to axis of the coordinate system and perform rough
6804 // analysis. If solution is not clear perform thorough analysis.
6806 const int nbAxes = 3;
6807 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6808 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6809 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6810 multimap< int, int > nbInt2Axis; // to find the simplest case
6811 for ( int axis = 0; axis < nbAxes; ++axis )
6813 gp_Ax1 lineAxis( point, axisDir[axis]);
6814 gp_Lin line ( lineAxis );
6816 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6817 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6819 // Intersect faces with the line
6821 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6822 TIDSortedElemSet::iterator face = suspectFaces.begin();
6823 for ( ; face != suspectFaces.end(); ++face )
6827 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6828 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6830 // perform intersection
6831 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6832 if ( !intersection.IsDone() )
6834 if ( intersection.IsInQuadric() )
6836 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6838 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6840 gp_Pnt intersectionPoint = intersection.Point(1);
6841 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6842 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6845 // Analyse intersections roughly
6847 int nbInter = u2inters.size();
6851 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6852 if ( nbInter == 1 ) // not closed mesh
6853 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6855 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6858 if ( (f<0) == (l<0) )
6861 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6862 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6863 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6866 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6868 if ( _outerFacesFound ) break; // pass to thorough analysis
6870 } // three attempts - loop on CS axes
6872 // Analyse intersections thoroughly.
6873 // We make two loops maximum, on the first one we only exclude touching intersections,
6874 // on the second, if situation is still unclear, we gather and use information on
6875 // position of faces (internal or outer). If faces position is already gathered,
6876 // we make the second loop right away.
6878 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6880 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6881 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6883 int axis = nb_axis->second;
6884 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6886 gp_Ax1 lineAxis( point, axisDir[axis]);
6887 gp_Lin line ( lineAxis );
6889 // add tangent intersections to u2inters
6891 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6892 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6893 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6894 u2inters.insert(make_pair( param, *tgtInt ));
6895 tangentInters[ axis ].clear();
6897 // Count intersections before and after the point excluding touching ones.
6898 // If hasPositionInfo we count intersections of outer boundary only
6900 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6901 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6902 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6903 bool ok = ! u_int1->second._coincides;
6904 while ( ok && u_int1 != u2inters.end() )
6906 double u = u_int1->first;
6907 bool touchingInt = false;
6908 if ( ++u_int2 != u2inters.end() )
6910 // skip intersections at the same point (if the line passes through edge or node)
6912 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6918 // skip tangent intersections
6920 const SMDS_MeshElement* prevFace = u_int1->second._face;
6921 while ( ok && u_int2->second._coincides )
6923 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6929 ok = ( u_int2 != u2inters.end() );
6934 // skip intersections at the same point after tangent intersections
6937 double u2 = u_int2->first;
6939 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6945 // decide if we skipped a touching intersection
6946 if ( nbSamePnt + nbTgt > 0 )
6948 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6949 map< double, TInters >::iterator u_int = u_int1;
6950 for ( ; u_int != u_int2; ++u_int )
6952 if ( u_int->second._coincides ) continue;
6953 double dot = u_int->second._faceNorm * line.Direction();
6954 if ( dot > maxDot ) maxDot = dot;
6955 if ( dot < minDot ) minDot = dot;
6957 touchingInt = ( minDot*maxDot < 0 );
6962 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6973 u_int1 = u_int2; // to next intersection
6975 } // loop on intersections with one line
6979 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6982 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6985 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6986 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6988 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6991 if ( (f<0) == (l<0) )
6994 if ( hasPositionInfo )
6995 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6997 } // loop on intersections of the tree lines - thorough analysis
6999 if ( !hasPositionInfo )
7001 // gather info on faces position - is face in the outer boundary or not
7002 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7003 findOuterBoundary( u2inters.begin()->second._face );
7006 } // two attempts - with and w/o faces position info in the mesh
7008 return TopAbs_UNKNOWN;
7011 //=======================================================================
7013 * \brief Return elements possibly intersecting the line
7015 //=======================================================================
7017 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7018 SMDSAbs_ElementType type,
7019 vector< const SMDS_MeshElement* >& foundElems)
7021 if ( !_ebbTree || _elementType != type )
7023 if ( _ebbTree ) delete _ebbTree;
7024 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
7026 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7027 _ebbTree->getElementsNearLine( line, suspectFaces );
7028 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7031 //=======================================================================
7033 * \brief Return SMESH_ElementSearcher
7035 //=======================================================================
7037 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7039 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7042 //=======================================================================
7044 * \brief Return true if the point is IN or ON of the element
7046 //=======================================================================
7048 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7050 if ( element->GetType() == SMDSAbs_Volume)
7052 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7055 // get ordered nodes
7057 vector< gp_XYZ > xyz;
7058 vector<const SMDS_MeshNode*> nodeList;
7060 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7061 if ( element->IsQuadratic() ) {
7062 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7063 nodeIt = f->interlacedNodesElemIterator();
7064 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7065 nodeIt = e->interlacedNodesElemIterator();
7067 while ( nodeIt->more() )
7069 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7070 xyz.push_back( TNodeXYZ(node) );
7071 nodeList.push_back(node);
7074 int i, nbNodes = element->NbNodes();
7076 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7078 // compute face normal
7079 gp_Vec faceNorm(0,0,0);
7080 xyz.push_back( xyz.front() );
7081 nodeList.push_back( nodeList.front() );
7082 for ( i = 0; i < nbNodes; ++i )
7084 gp_Vec edge1( xyz[i+1], xyz[i]);
7085 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7086 faceNorm += edge1 ^ edge2;
7088 double normSize = faceNorm.Magnitude();
7089 if ( normSize <= tol )
7091 // degenerated face: point is out if it is out of all face edges
7092 for ( i = 0; i < nbNodes; ++i )
7094 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7095 if ( !isOut( &edge, point, tol ))
7100 faceNorm /= normSize;
7102 // check if the point lays on face plane
7103 gp_Vec n2p( xyz[0], point );
7104 if ( fabs( n2p * faceNorm ) > tol )
7105 return true; // not on face plane
7107 // check if point is out of face boundary:
7108 // define it by closest transition of a ray point->infinity through face boundary
7109 // on the face plane.
7110 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7111 // to find intersections of the ray with the boundary.
7113 gp_Vec plnNorm = ray ^ faceNorm;
7114 normSize = plnNorm.Magnitude();
7115 if ( normSize <= tol ) return false; // point coincides with the first node
7116 plnNorm /= normSize;
7117 // for each node of the face, compute its signed distance to the plane
7118 vector<double> dist( nbNodes + 1);
7119 for ( i = 0; i < nbNodes; ++i )
7121 gp_Vec n2p( xyz[i], point );
7122 dist[i] = n2p * plnNorm;
7124 dist.back() = dist.front();
7125 // find the closest intersection
7127 double rClosest, distClosest = 1e100;;
7129 for ( i = 0; i < nbNodes; ++i )
7132 if ( fabs( dist[i]) < tol )
7134 else if ( fabs( dist[i+1]) < tol )
7136 else if ( dist[i] * dist[i+1] < 0 )
7137 r = dist[i] / ( dist[i] - dist[i+1] );
7139 continue; // no intersection
7140 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7141 gp_Vec p2int ( point, pInt);
7142 if ( p2int * ray > -tol ) // right half-space
7144 double intDist = p2int.SquareMagnitude();
7145 if ( intDist < distClosest )
7150 distClosest = intDist;
7155 return true; // no intesections - out
7157 // analyse transition
7158 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7159 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7160 gp_Vec p2int ( point, pClosest );
7161 bool out = (edgeNorm * p2int) < -tol;
7162 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7165 // ray pass through a face node; analyze transition through an adjacent edge
7166 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7167 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7168 gp_Vec edgeAdjacent( p1, p2 );
7169 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7170 bool out2 = (edgeNorm2 * p2int) < -tol;
7172 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7173 return covexCorner ? (out || out2) : (out && out2);
7175 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7177 // point is out of edge if it is NOT ON any straight part of edge
7178 // (we consider quadratic edge as being composed of two straight parts)
7179 for ( i = 1; i < nbNodes; ++i )
7181 gp_Vec edge( xyz[i-1], xyz[i]);
7182 gp_Vec n1p ( xyz[i-1], point);
7183 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7186 gp_Vec n2p( xyz[i], point );
7187 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7189 return false; // point is ON this part
7193 // Node or 0D element -------------------------------------------------------------------------
7195 gp_Vec n2p ( xyz[0], point );
7196 return n2p.Magnitude() <= tol;
7201 //=======================================================================
7202 //function : SimplifyFace
7204 //=======================================================================
7205 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7206 vector<const SMDS_MeshNode *>& poly_nodes,
7207 vector<int>& quantities) const
7209 int nbNodes = faceNodes.size();
7214 set<const SMDS_MeshNode*> nodeSet;
7216 // get simple seq of nodes
7217 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7218 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7219 int iSimple = 0, nbUnique = 0;
7221 simpleNodes[iSimple++] = faceNodes[0];
7223 for (int iCur = 1; iCur < nbNodes; iCur++) {
7224 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7225 simpleNodes[iSimple++] = faceNodes[iCur];
7226 if (nodeSet.insert( faceNodes[iCur] ).second)
7230 int nbSimple = iSimple;
7231 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7241 bool foundLoop = (nbSimple > nbUnique);
7244 set<const SMDS_MeshNode*> loopSet;
7245 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7246 const SMDS_MeshNode* n = simpleNodes[iSimple];
7247 if (!loopSet.insert( n ).second) {
7251 int iC = 0, curLast = iSimple;
7252 for (; iC < curLast; iC++) {
7253 if (simpleNodes[iC] == n) break;
7255 int loopLen = curLast - iC;
7257 // create sub-element
7259 quantities.push_back(loopLen);
7260 for (; iC < curLast; iC++) {
7261 poly_nodes.push_back(simpleNodes[iC]);
7264 // shift the rest nodes (place from the first loop position)
7265 for (iC = curLast + 1; iC < nbSimple; iC++) {
7266 simpleNodes[iC - loopLen] = simpleNodes[iC];
7268 nbSimple -= loopLen;
7271 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7272 } // while (foundLoop)
7276 quantities.push_back(iSimple);
7277 for (int i = 0; i < iSimple; i++)
7278 poly_nodes.push_back(simpleNodes[i]);
7284 //=======================================================================
7285 //function : MergeNodes
7286 //purpose : In each group, the cdr of nodes are substituted by the first one
7288 //=======================================================================
7290 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7292 MESSAGE("MergeNodes");
7293 myLastCreatedElems.Clear();
7294 myLastCreatedNodes.Clear();
7296 SMESHDS_Mesh* aMesh = GetMeshDS();
7298 TNodeNodeMap nodeNodeMap; // node to replace - new node
7299 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7300 list< int > rmElemIds, rmNodeIds;
7302 // Fill nodeNodeMap and elems
7304 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7305 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7306 list<const SMDS_MeshNode*>& nodes = *grIt;
7307 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7308 const SMDS_MeshNode* nToKeep = *nIt;
7309 //MESSAGE("node to keep " << nToKeep->GetID());
7310 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7311 const SMDS_MeshNode* nToRemove = *nIt;
7312 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7313 if ( nToRemove != nToKeep ) {
7314 //MESSAGE(" node to remove " << nToRemove->GetID());
7315 rmNodeIds.push_back( nToRemove->GetID() );
7316 AddToSameGroups( nToKeep, nToRemove, aMesh );
7319 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7320 while ( invElemIt->more() ) {
7321 const SMDS_MeshElement* elem = invElemIt->next();
7326 // Change element nodes or remove an element
7328 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7329 for ( ; eIt != elems.end(); eIt++ ) {
7330 const SMDS_MeshElement* elem = *eIt;
7331 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7332 int nbNodes = elem->NbNodes();
7333 int aShapeId = FindShape( elem );
7335 set<const SMDS_MeshNode*> nodeSet;
7336 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7337 int iUnique = 0, iCur = 0, nbRepl = 0;
7338 vector<int> iRepl( nbNodes );
7340 // get new seq of nodes
7341 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7342 while ( itN->more() ) {
7343 const SMDS_MeshNode* n =
7344 static_cast<const SMDS_MeshNode*>( itN->next() );
7346 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7347 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7349 // BUG 0020185: begin
7351 bool stopRecur = false;
7352 set<const SMDS_MeshNode*> nodesRecur;
7353 nodesRecur.insert(n);
7354 while (!stopRecur) {
7355 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7356 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7357 n = (*nnIt_i).second;
7358 if (!nodesRecur.insert(n).second) {
7359 // error: recursive dependancy
7368 iRepl[ nbRepl++ ] = iCur;
7370 curNodes[ iCur ] = n;
7371 bool isUnique = nodeSet.insert( n ).second;
7373 uniqueNodes[ iUnique++ ] = n;
7377 // Analyse element topology after replacement
7380 int nbUniqueNodes = nodeSet.size();
7381 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7382 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7383 // Polygons and Polyhedral volumes
7384 if (elem->IsPoly()) {
7386 if (elem->GetType() == SMDSAbs_Face) {
7388 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7390 for (; inode < nbNodes; inode++) {
7391 face_nodes[inode] = curNodes[inode];
7394 vector<const SMDS_MeshNode *> polygons_nodes;
7395 vector<int> quantities;
7396 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7399 for (int iface = 0; iface < nbNew; iface++) {
7400 int nbNodes = quantities[iface];
7401 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7402 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7403 poly_nodes[ii] = polygons_nodes[inode];
7405 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7406 myLastCreatedElems.Append(newElem);
7408 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7411 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7412 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7413 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7415 if (nbNew > 0) quid = nbNew - 1;
7416 vector<int> newquant(quantities.begin()+quid, quantities.end());
7417 const SMDS_MeshElement* newElem = 0;
7418 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7419 myLastCreatedElems.Append(newElem);
7420 if ( aShapeId && newElem )
7421 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7422 rmElemIds.push_back(elem->GetID());
7425 rmElemIds.push_back(elem->GetID());
7429 else if (elem->GetType() == SMDSAbs_Volume) {
7430 // Polyhedral volume
7431 if (nbUniqueNodes < 4) {
7432 rmElemIds.push_back(elem->GetID());
7435 // each face has to be analyzed in order to check volume validity
7436 const SMDS_VtkVolume* aPolyedre =
7437 dynamic_cast<const SMDS_VtkVolume*>( elem );
7439 int nbFaces = aPolyedre->NbFaces();
7441 vector<const SMDS_MeshNode *> poly_nodes;
7442 vector<int> quantities;
7444 for (int iface = 1; iface <= nbFaces; iface++) {
7445 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7446 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7448 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7449 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7450 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7451 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7452 faceNode = (*nnIt).second;
7454 faceNodes[inode - 1] = faceNode;
7457 SimplifyFace(faceNodes, poly_nodes, quantities);
7460 if (quantities.size() > 3) {
7461 // to be done: remove coincident faces
7464 if (quantities.size() > 3)
7466 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7467 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7468 const SMDS_MeshElement* newElem = 0;
7469 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7470 myLastCreatedElems.Append(newElem);
7471 if ( aShapeId && newElem )
7472 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7473 rmElemIds.push_back(elem->GetID());
7477 rmElemIds.push_back(elem->GetID());
7488 // TODO not all the possible cases are solved. Find something more generic?
7489 switch ( nbNodes ) {
7490 case 2: ///////////////////////////////////// EDGE
7491 isOk = false; break;
7492 case 3: ///////////////////////////////////// TRIANGLE
7493 isOk = false; break;
7495 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7497 else { //////////////////////////////////// QUADRANGLE
7498 if ( nbUniqueNodes < 3 )
7500 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7501 isOk = false; // opposite nodes stick
7502 //MESSAGE("isOk " << isOk);
7505 case 6: ///////////////////////////////////// PENTAHEDRON
7506 if ( nbUniqueNodes == 4 ) {
7507 // ---------------------------------> tetrahedron
7509 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7510 // all top nodes stick: reverse a bottom
7511 uniqueNodes[ 0 ] = curNodes [ 1 ];
7512 uniqueNodes[ 1 ] = curNodes [ 0 ];
7514 else if (nbRepl == 3 &&
7515 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7516 // all bottom nodes stick: set a top before
7517 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7518 uniqueNodes[ 0 ] = curNodes [ 3 ];
7519 uniqueNodes[ 1 ] = curNodes [ 4 ];
7520 uniqueNodes[ 2 ] = curNodes [ 5 ];
7522 else if (nbRepl == 4 &&
7523 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7524 // a lateral face turns into a line: reverse a bottom
7525 uniqueNodes[ 0 ] = curNodes [ 1 ];
7526 uniqueNodes[ 1 ] = curNodes [ 0 ];
7531 else if ( nbUniqueNodes == 5 ) {
7532 // PENTAHEDRON --------------------> 2 tetrahedrons
7533 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7534 // a bottom node sticks with a linked top one
7536 SMDS_MeshElement* newElem =
7537 aMesh->AddVolume(curNodes[ 3 ],
7540 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7541 myLastCreatedElems.Append(newElem);
7543 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7544 // 2. : reverse a bottom
7545 uniqueNodes[ 0 ] = curNodes [ 1 ];
7546 uniqueNodes[ 1 ] = curNodes [ 0 ];
7556 if(elem->IsQuadratic()) { // Quadratic quadrangle
7568 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7571 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7573 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7574 uniqueNodes[0] = curNodes[0];
7575 uniqueNodes[1] = curNodes[2];
7576 uniqueNodes[2] = curNodes[3];
7577 uniqueNodes[3] = curNodes[5];
7578 uniqueNodes[4] = curNodes[6];
7579 uniqueNodes[5] = curNodes[7];
7582 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7583 uniqueNodes[0] = curNodes[0];
7584 uniqueNodes[1] = curNodes[1];
7585 uniqueNodes[2] = curNodes[2];
7586 uniqueNodes[3] = curNodes[4];
7587 uniqueNodes[4] = curNodes[5];
7588 uniqueNodes[5] = curNodes[6];
7591 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7592 uniqueNodes[0] = curNodes[1];
7593 uniqueNodes[1] = curNodes[2];
7594 uniqueNodes[2] = curNodes[3];
7595 uniqueNodes[3] = curNodes[5];
7596 uniqueNodes[4] = curNodes[6];
7597 uniqueNodes[5] = curNodes[0];
7600 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7601 uniqueNodes[0] = curNodes[0];
7602 uniqueNodes[1] = curNodes[1];
7603 uniqueNodes[2] = curNodes[3];
7604 uniqueNodes[3] = curNodes[4];
7605 uniqueNodes[4] = curNodes[6];
7606 uniqueNodes[5] = curNodes[7];
7609 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7610 uniqueNodes[0] = curNodes[0];
7611 uniqueNodes[1] = curNodes[2];
7612 uniqueNodes[2] = curNodes[3];
7613 uniqueNodes[3] = curNodes[1];
7614 uniqueNodes[4] = curNodes[6];
7615 uniqueNodes[5] = curNodes[7];
7618 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7619 uniqueNodes[0] = curNodes[0];
7620 uniqueNodes[1] = curNodes[1];
7621 uniqueNodes[2] = curNodes[2];
7622 uniqueNodes[3] = curNodes[4];
7623 uniqueNodes[4] = curNodes[5];
7624 uniqueNodes[5] = curNodes[7];
7627 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7628 uniqueNodes[0] = curNodes[0];
7629 uniqueNodes[1] = curNodes[1];
7630 uniqueNodes[2] = curNodes[3];
7631 uniqueNodes[3] = curNodes[4];
7632 uniqueNodes[4] = curNodes[2];
7633 uniqueNodes[5] = curNodes[7];
7636 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7637 uniqueNodes[0] = curNodes[0];
7638 uniqueNodes[1] = curNodes[1];
7639 uniqueNodes[2] = curNodes[2];
7640 uniqueNodes[3] = curNodes[4];
7641 uniqueNodes[4] = curNodes[5];
7642 uniqueNodes[5] = curNodes[3];
7647 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7650 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7654 //////////////////////////////////// HEXAHEDRON
7656 SMDS_VolumeTool hexa (elem);
7657 hexa.SetExternalNormal();
7658 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7659 //////////////////////// ---> tetrahedron
7660 for ( int iFace = 0; iFace < 6; iFace++ ) {
7661 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7662 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7663 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7664 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7665 // one face turns into a point ...
7666 int iOppFace = hexa.GetOppFaceIndex( iFace );
7667 ind = hexa.GetFaceNodesIndices( iOppFace );
7669 iUnique = 2; // reverse a tetrahedron bottom
7670 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7671 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7673 else if ( iUnique >= 0 )
7674 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7676 if ( nbStick == 1 ) {
7677 // ... and the opposite one - into a triangle.
7679 ind = hexa.GetFaceNodesIndices( iFace );
7680 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7687 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7688 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7689 for ( int iFace = 0; iFace < 6; iFace++ ) {
7690 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7691 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7692 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7693 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7694 // one face turns into a point ...
7695 int iOppFace = hexa.GetOppFaceIndex( iFace );
7696 ind = hexa.GetFaceNodesIndices( iOppFace );
7698 iUnique = 2; // reverse a tetrahedron 1 bottom
7699 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7700 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7702 else if ( iUnique >= 0 )
7703 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7705 if ( nbStick == 0 ) {
7706 // ... and the opposite one is a quadrangle
7708 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7709 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7712 SMDS_MeshElement* newElem =
7713 aMesh->AddVolume(curNodes[ind[ 0 ]],
7716 curNodes[indTop[ 0 ]]);
7717 myLastCreatedElems.Append(newElem);
7719 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7726 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7727 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7728 // find indices of quad and tri faces
7729 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7730 for ( iFace = 0; iFace < 6; iFace++ ) {
7731 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7733 for ( iCur = 0; iCur < 4; iCur++ )
7734 nodeSet.insert( curNodes[ind[ iCur ]] );
7735 nbUniqueNodes = nodeSet.size();
7736 if ( nbUniqueNodes == 3 )
7737 iTriFace[ nbTri++ ] = iFace;
7738 else if ( nbUniqueNodes == 4 )
7739 iQuadFace[ nbQuad++ ] = iFace;
7741 if (nbQuad == 2 && nbTri == 4 &&
7742 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7743 // 2 opposite quadrangles stuck with a diagonal;
7744 // sample groups of merged indices: (0-4)(2-6)
7745 // --------------------------------------------> 2 tetrahedrons
7746 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7747 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7748 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7749 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7750 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7751 // stuck with 0-2 diagonal
7759 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7760 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7761 // stuck with 1-3 diagonal
7773 uniqueNodes[ 0 ] = curNodes [ i0 ];
7774 uniqueNodes[ 1 ] = curNodes [ i1d ];
7775 uniqueNodes[ 2 ] = curNodes [ i3d ];
7776 uniqueNodes[ 3 ] = curNodes [ i0t ];
7779 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7783 myLastCreatedElems.Append(newElem);
7785 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7788 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7789 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7790 // --------------------------------------------> prism
7791 // find 2 opposite triangles
7793 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7794 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7795 // find indices of kept and replaced nodes
7796 // and fill unique nodes of 2 opposite triangles
7797 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7798 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7799 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7800 // fill unique nodes
7803 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7804 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7805 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7807 // iCur of a linked node of the opposite face (make normals co-directed):
7808 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7809 // check that correspondent corners of triangles are linked
7810 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7813 uniqueNodes[ iUnique ] = n;
7814 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7823 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7829 } // switch ( nbNodes )
7831 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7834 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7835 // Change nodes of polyedre
7836 const SMDS_VtkVolume* aPolyedre =
7837 dynamic_cast<const SMDS_VtkVolume*>( elem );
7839 int nbFaces = aPolyedre->NbFaces();
7841 vector<const SMDS_MeshNode *> poly_nodes;
7842 vector<int> quantities (nbFaces);
7844 for (int iface = 1; iface <= nbFaces; iface++) {
7845 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7846 quantities[iface - 1] = nbFaceNodes;
7848 for (inode = 1; inode <= nbFaceNodes; inode++) {
7849 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7851 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7852 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7853 curNode = (*nnIt).second;
7855 poly_nodes.push_back(curNode);
7858 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7862 //int elemId = elem->GetID();
7863 //MESSAGE("Change regular element or polygon " << elemId);
7864 SMDSAbs_ElementType etyp = elem->GetType();
7865 uniqueNodes.resize(nbUniqueNodes);
7866 SMDS_MeshElement* newElem = 0;
7867 if (elem->GetEntityType() == SMDSEntity_Polygon)
7868 newElem = this->AddElement(uniqueNodes, etyp, true);
7870 newElem = this->AddElement(uniqueNodes, etyp, false);
7873 myLastCreatedElems.Append(newElem);
7875 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7877 aMesh->RemoveElement(elem);
7881 // Remove invalid regular element or invalid polygon
7882 //MESSAGE("Remove invalid " << elem->GetID());
7883 rmElemIds.push_back( elem->GetID() );
7886 } // loop on elements
7888 // Remove bad elements, then equal nodes (order important)
7890 Remove( rmElemIds, false );
7891 Remove( rmNodeIds, true );
7896 // ========================================================
7897 // class : SortableElement
7898 // purpose : allow sorting elements basing on their nodes
7899 // ========================================================
7900 class SortableElement : public set <const SMDS_MeshElement*>
7904 SortableElement( const SMDS_MeshElement* theElem )
7907 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7908 while ( nodeIt->more() )
7909 this->insert( nodeIt->next() );
7912 const SMDS_MeshElement* Get() const
7915 void Set(const SMDS_MeshElement* e) const
7920 mutable const SMDS_MeshElement* myElem;
7923 //=======================================================================
7924 //function : FindEqualElements
7925 //purpose : Return list of group of elements built on the same nodes.
7926 // Search among theElements or in the whole mesh if theElements is empty
7927 //=======================================================================
7928 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7929 TListOfListOfElementsID & theGroupsOfElementsID)
7931 myLastCreatedElems.Clear();
7932 myLastCreatedNodes.Clear();
7934 typedef set<const SMDS_MeshElement*> TElemsSet;
7935 typedef map< SortableElement, int > TMapOfNodeSet;
7936 typedef list<int> TGroupOfElems;
7939 if ( theElements.empty() )
7940 { // get all elements in the mesh
7941 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7942 while ( eIt->more() )
7943 elems.insert( elems.end(), eIt->next());
7946 elems = theElements;
7948 vector< TGroupOfElems > arrayOfGroups;
7949 TGroupOfElems groupOfElems;
7950 TMapOfNodeSet mapOfNodeSet;
7952 TElemsSet::iterator elemIt = elems.begin();
7953 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7954 const SMDS_MeshElement* curElem = *elemIt;
7955 SortableElement SE(curElem);
7958 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7959 if( !(pp.second) ) {
7960 TMapOfNodeSet::iterator& itSE = pp.first;
7961 ind = (*itSE).second;
7962 arrayOfGroups[ind].push_back(curElem->GetID());
7965 groupOfElems.clear();
7966 groupOfElems.push_back(curElem->GetID());
7967 arrayOfGroups.push_back(groupOfElems);
7972 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7973 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7974 groupOfElems = *groupIt;
7975 if ( groupOfElems.size() > 1 ) {
7976 groupOfElems.sort();
7977 theGroupsOfElementsID.push_back(groupOfElems);
7982 //=======================================================================
7983 //function : MergeElements
7984 //purpose : In each given group, substitute all elements by the first one.
7985 //=======================================================================
7987 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7989 myLastCreatedElems.Clear();
7990 myLastCreatedNodes.Clear();
7992 typedef list<int> TListOfIDs;
7993 TListOfIDs rmElemIds; // IDs of elems to remove
7995 SMESHDS_Mesh* aMesh = GetMeshDS();
7997 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7998 while ( groupsIt != theGroupsOfElementsID.end() ) {
7999 TListOfIDs& aGroupOfElemID = *groupsIt;
8000 aGroupOfElemID.sort();
8001 int elemIDToKeep = aGroupOfElemID.front();
8002 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8003 aGroupOfElemID.pop_front();
8004 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8005 while ( idIt != aGroupOfElemID.end() ) {
8006 int elemIDToRemove = *idIt;
8007 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8008 // add the kept element in groups of removed one (PAL15188)
8009 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8010 rmElemIds.push_back( elemIDToRemove );
8016 Remove( rmElemIds, false );
8019 //=======================================================================
8020 //function : MergeEqualElements
8021 //purpose : Remove all but one of elements built on the same nodes.
8022 //=======================================================================
8024 void SMESH_MeshEditor::MergeEqualElements()
8026 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8027 to merge equal elements in the whole mesh */
8028 TListOfListOfElementsID aGroupsOfElementsID;
8029 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8030 MergeElements(aGroupsOfElementsID);
8033 //=======================================================================
8034 //function : FindFaceInSet
8035 //purpose : Return a face having linked nodes n1 and n2 and which is
8036 // - not in avoidSet,
8037 // - in elemSet provided that !elemSet.empty()
8038 // i1 and i2 optionally returns indices of n1 and n2
8039 //=======================================================================
8041 const SMDS_MeshElement*
8042 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8043 const SMDS_MeshNode* n2,
8044 const TIDSortedElemSet& elemSet,
8045 const TIDSortedElemSet& avoidSet,
8051 const SMDS_MeshElement* face = 0;
8053 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8054 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8055 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8057 //MESSAGE("in while ( invElemIt->more() && !face )");
8058 const SMDS_MeshElement* elem = invElemIt->next();
8059 if (avoidSet.count( elem ))
8061 if ( !elemSet.empty() && !elemSet.count( elem ))
8064 i1 = elem->GetNodeIndex( n1 );
8065 // find a n2 linked to n1
8066 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8067 for ( int di = -1; di < 2 && !face; di += 2 )
8069 i2 = (i1+di+nbN) % nbN;
8070 if ( elem->GetNode( i2 ) == n2 )
8073 if ( !face && elem->IsQuadratic())
8075 // analysis for quadratic elements using all nodes
8076 const SMDS_VtkFace* F =
8077 dynamic_cast<const SMDS_VtkFace*>(elem);
8078 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8079 // use special nodes iterator
8080 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8081 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8082 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8084 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8085 if ( n1 == prevN && n2 == n )
8089 else if ( n2 == prevN && n1 == n )
8091 face = elem; swap( i1, i2 );
8097 if ( n1ind ) *n1ind = i1;
8098 if ( n2ind ) *n2ind = i2;
8102 //=======================================================================
8103 //function : findAdjacentFace
8105 //=======================================================================
8107 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8108 const SMDS_MeshNode* n2,
8109 const SMDS_MeshElement* elem)
8111 TIDSortedElemSet elemSet, avoidSet;
8113 avoidSet.insert ( elem );
8114 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8117 //=======================================================================
8118 //function : FindFreeBorder
8120 //=======================================================================
8122 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8124 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8125 const SMDS_MeshNode* theSecondNode,
8126 const SMDS_MeshNode* theLastNode,
8127 list< const SMDS_MeshNode* > & theNodes,
8128 list< const SMDS_MeshElement* >& theFaces)
8130 if ( !theFirstNode || !theSecondNode )
8132 // find border face between theFirstNode and theSecondNode
8133 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8137 theFaces.push_back( curElem );
8138 theNodes.push_back( theFirstNode );
8139 theNodes.push_back( theSecondNode );
8141 //vector<const SMDS_MeshNode*> nodes;
8142 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8143 TIDSortedElemSet foundElems;
8144 bool needTheLast = ( theLastNode != 0 );
8146 while ( nStart != theLastNode ) {
8147 if ( nStart == theFirstNode )
8148 return !needTheLast;
8150 // find all free border faces sharing form nStart
8152 list< const SMDS_MeshElement* > curElemList;
8153 list< const SMDS_MeshNode* > nStartList;
8154 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8155 while ( invElemIt->more() ) {
8156 const SMDS_MeshElement* e = invElemIt->next();
8157 if ( e == curElem || foundElems.insert( e ).second ) {
8159 int iNode = 0, nbNodes = e->NbNodes();
8160 //const SMDS_MeshNode* nodes[nbNodes+1];
8161 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8163 if(e->IsQuadratic()) {
8164 const SMDS_VtkFace* F =
8165 dynamic_cast<const SMDS_VtkFace*>(e);
8166 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8167 // use special nodes iterator
8168 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8169 while( anIter->more() ) {
8170 nodes[ iNode++ ] = cast2Node(anIter->next());
8174 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8175 while ( nIt->more() )
8176 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8178 nodes[ iNode ] = nodes[ 0 ];
8180 for ( iNode = 0; iNode < nbNodes; iNode++ )
8181 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8182 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8183 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8185 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8186 curElemList.push_back( e );
8190 // analyse the found
8192 int nbNewBorders = curElemList.size();
8193 if ( nbNewBorders == 0 ) {
8194 // no free border furthermore
8195 return !needTheLast;
8197 else if ( nbNewBorders == 1 ) {
8198 // one more element found
8200 nStart = nStartList.front();
8201 curElem = curElemList.front();
8202 theFaces.push_back( curElem );
8203 theNodes.push_back( nStart );
8206 // several continuations found
8207 list< const SMDS_MeshElement* >::iterator curElemIt;
8208 list< const SMDS_MeshNode* >::iterator nStartIt;
8209 // check if one of them reached the last node
8210 if ( needTheLast ) {
8211 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8212 curElemIt!= curElemList.end();
8213 curElemIt++, nStartIt++ )
8214 if ( *nStartIt == theLastNode ) {
8215 theFaces.push_back( *curElemIt );
8216 theNodes.push_back( *nStartIt );
8220 // find the best free border by the continuations
8221 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8222 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8223 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8224 curElemIt!= curElemList.end();
8225 curElemIt++, nStartIt++ )
8227 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8228 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8229 // find one more free border
8230 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8234 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8235 // choice: clear a worse one
8236 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8237 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8238 contNodes[ iWorse ].clear();
8239 contFaces[ iWorse ].clear();
8242 if ( contNodes[0].empty() && contNodes[1].empty() )
8245 // append the best free border
8246 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8247 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8248 theNodes.pop_back(); // remove nIgnore
8249 theNodes.pop_back(); // remove nStart
8250 theFaces.pop_back(); // remove curElem
8251 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8252 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8253 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8254 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8257 } // several continuations found
8258 } // while ( nStart != theLastNode )
8263 //=======================================================================
8264 //function : CheckFreeBorderNodes
8265 //purpose : Return true if the tree nodes are on a free border
8266 //=======================================================================
8268 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8269 const SMDS_MeshNode* theNode2,
8270 const SMDS_MeshNode* theNode3)
8272 list< const SMDS_MeshNode* > nodes;
8273 list< const SMDS_MeshElement* > faces;
8274 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8277 //=======================================================================
8278 //function : SewFreeBorder
8280 //=======================================================================
8282 SMESH_MeshEditor::Sew_Error
8283 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8284 const SMDS_MeshNode* theBordSecondNode,
8285 const SMDS_MeshNode* theBordLastNode,
8286 const SMDS_MeshNode* theSideFirstNode,
8287 const SMDS_MeshNode* theSideSecondNode,
8288 const SMDS_MeshNode* theSideThirdNode,
8289 const bool theSideIsFreeBorder,
8290 const bool toCreatePolygons,
8291 const bool toCreatePolyedrs)
8293 myLastCreatedElems.Clear();
8294 myLastCreatedNodes.Clear();
8296 MESSAGE("::SewFreeBorder()");
8297 Sew_Error aResult = SEW_OK;
8299 // ====================================
8300 // find side nodes and elements
8301 // ====================================
8303 list< const SMDS_MeshNode* > nSide[ 2 ];
8304 list< const SMDS_MeshElement* > eSide[ 2 ];
8305 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8306 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8310 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8311 nSide[0], eSide[0])) {
8312 MESSAGE(" Free Border 1 not found " );
8313 aResult = SEW_BORDER1_NOT_FOUND;
8315 if (theSideIsFreeBorder) {
8318 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8319 nSide[1], eSide[1])) {
8320 MESSAGE(" Free Border 2 not found " );
8321 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8324 if ( aResult != SEW_OK )
8327 if (!theSideIsFreeBorder) {
8331 // -------------------------------------------------------------------------
8333 // 1. If nodes to merge are not coincident, move nodes of the free border
8334 // from the coord sys defined by the direction from the first to last
8335 // nodes of the border to the correspondent sys of the side 2
8336 // 2. On the side 2, find the links most co-directed with the correspondent
8337 // links of the free border
8338 // -------------------------------------------------------------------------
8340 // 1. Since sewing may break if there are volumes to split on the side 2,
8341 // we wont move nodes but just compute new coordinates for them
8342 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8343 TNodeXYZMap nBordXYZ;
8344 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8345 list< const SMDS_MeshNode* >::iterator nBordIt;
8347 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8348 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8349 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8350 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8351 double tol2 = 1.e-8;
8352 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8353 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8354 // Need node movement.
8356 // find X and Z axes to create trsf
8357 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8359 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8361 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8364 gp_Ax3 toBordAx( Pb1, Zb, X );
8365 gp_Ax3 fromSideAx( Ps1, Zs, X );
8366 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8368 gp_Trsf toBordSys, fromSide2Sys;
8369 toBordSys.SetTransformation( toBordAx );
8370 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8371 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8374 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8375 const SMDS_MeshNode* n = *nBordIt;
8376 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8377 toBordSys.Transforms( xyz );
8378 fromSide2Sys.Transforms( xyz );
8379 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8383 // just insert nodes XYZ in the nBordXYZ map
8384 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8385 const SMDS_MeshNode* n = *nBordIt;
8386 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8390 // 2. On the side 2, find the links most co-directed with the correspondent
8391 // links of the free border
8393 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8394 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8395 sideNodes.push_back( theSideFirstNode );
8397 bool hasVolumes = false;
8398 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8399 set<long> foundSideLinkIDs, checkedLinkIDs;
8400 SMDS_VolumeTool volume;
8401 //const SMDS_MeshNode* faceNodes[ 4 ];
8403 const SMDS_MeshNode* sideNode;
8404 const SMDS_MeshElement* sideElem;
8405 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8406 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8407 nBordIt = bordNodes.begin();
8409 // border node position and border link direction to compare with
8410 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8411 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8412 // choose next side node by link direction or by closeness to
8413 // the current border node:
8414 bool searchByDir = ( *nBordIt != theBordLastNode );
8416 // find the next node on the Side 2
8418 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8420 checkedLinkIDs.clear();
8421 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8423 // loop on inverse elements of current node (prevSideNode) on the Side 2
8424 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8425 while ( invElemIt->more() )
8427 const SMDS_MeshElement* elem = invElemIt->next();
8428 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8429 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8430 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8431 bool isVolume = volume.Set( elem );
8432 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8433 if ( isVolume ) // --volume
8435 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8436 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8437 if(elem->IsQuadratic()) {
8438 const SMDS_VtkFace* F =
8439 dynamic_cast<const SMDS_VtkFace*>(elem);
8440 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8441 // use special nodes iterator
8442 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8443 while( anIter->more() ) {
8444 nodes[ iNode ] = cast2Node(anIter->next());
8445 if ( nodes[ iNode++ ] == prevSideNode )
8446 iPrevNode = iNode - 1;
8450 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8451 while ( nIt->more() ) {
8452 nodes[ iNode ] = cast2Node( nIt->next() );
8453 if ( nodes[ iNode++ ] == prevSideNode )
8454 iPrevNode = iNode - 1;
8457 // there are 2 links to check
8462 // loop on links, to be precise, on the second node of links
8463 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8464 const SMDS_MeshNode* n = nodes[ iNode ];
8466 if ( !volume.IsLinked( n, prevSideNode ))
8470 if ( iNode ) // a node before prevSideNode
8471 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8472 else // a node after prevSideNode
8473 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8475 // check if this link was already used
8476 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8477 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8478 if (!isJustChecked &&
8479 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8481 // test a link geometrically
8482 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8483 bool linkIsBetter = false;
8484 double dot = 0.0, dist = 0.0;
8485 if ( searchByDir ) { // choose most co-directed link
8486 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8487 linkIsBetter = ( dot > maxDot );
8489 else { // choose link with the node closest to bordPos
8490 dist = ( nextXYZ - bordPos ).SquareModulus();
8491 linkIsBetter = ( dist < minDist );
8493 if ( linkIsBetter ) {
8502 } // loop on inverse elements of prevSideNode
8505 MESSAGE(" Cant find path by links of the Side 2 ");
8506 return SEW_BAD_SIDE_NODES;
8508 sideNodes.push_back( sideNode );
8509 sideElems.push_back( sideElem );
8510 foundSideLinkIDs.insert ( linkID );
8511 prevSideNode = sideNode;
8513 if ( *nBordIt == theBordLastNode )
8514 searchByDir = false;
8516 // find the next border link to compare with
8517 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8518 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8519 // move to next border node if sideNode is before forward border node (bordPos)
8520 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8521 prevBordNode = *nBordIt;
8523 bordPos = nBordXYZ[ *nBordIt ];
8524 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8525 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8529 while ( sideNode != theSideSecondNode );
8531 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8532 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8533 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8535 } // end nodes search on the side 2
8537 // ============================
8538 // sew the border to the side 2
8539 // ============================
8541 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8542 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8544 TListOfListOfNodes nodeGroupsToMerge;
8545 if ( nbNodes[0] == nbNodes[1] ||
8546 ( theSideIsFreeBorder && !theSideThirdNode)) {
8548 // all nodes are to be merged
8550 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8551 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8552 nIt[0]++, nIt[1]++ )
8554 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8555 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8556 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8561 // insert new nodes into the border and the side to get equal nb of segments
8563 // get normalized parameters of nodes on the borders
8564 //double param[ 2 ][ maxNbNodes ];
8566 param[0] = new double [ maxNbNodes ];
8567 param[1] = new double [ maxNbNodes ];
8569 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8570 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8571 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8572 const SMDS_MeshNode* nPrev = *nIt;
8573 double bordLength = 0;
8574 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8575 const SMDS_MeshNode* nCur = *nIt;
8576 gp_XYZ segment (nCur->X() - nPrev->X(),
8577 nCur->Y() - nPrev->Y(),
8578 nCur->Z() - nPrev->Z());
8579 double segmentLen = segment.Modulus();
8580 bordLength += segmentLen;
8581 param[ iBord ][ iNode ] = bordLength;
8584 // normalize within [0,1]
8585 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8586 param[ iBord ][ iNode ] /= bordLength;
8590 // loop on border segments
8591 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8592 int i[ 2 ] = { 0, 0 };
8593 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8594 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8596 TElemOfNodeListMap insertMap;
8597 TElemOfNodeListMap::iterator insertMapIt;
8599 // key: elem to insert nodes into
8600 // value: 2 nodes to insert between + nodes to be inserted
8602 bool next[ 2 ] = { false, false };
8604 // find min adjacent segment length after sewing
8605 double nextParam = 10., prevParam = 0;
8606 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8607 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8608 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8609 if ( i[ iBord ] > 0 )
8610 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8612 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8613 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8614 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8616 // choose to insert or to merge nodes
8617 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8618 if ( Abs( du ) <= minSegLen * 0.2 ) {
8621 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8622 const SMDS_MeshNode* n0 = *nIt[0];
8623 const SMDS_MeshNode* n1 = *nIt[1];
8624 nodeGroupsToMerge.back().push_back( n1 );
8625 nodeGroupsToMerge.back().push_back( n0 );
8626 // position of node of the border changes due to merge
8627 param[ 0 ][ i[0] ] += du;
8628 // move n1 for the sake of elem shape evaluation during insertion.
8629 // n1 will be removed by MergeNodes() anyway
8630 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8631 next[0] = next[1] = true;
8636 int intoBord = ( du < 0 ) ? 0 : 1;
8637 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8638 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8639 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8640 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8641 if ( intoBord == 1 ) {
8642 // move node of the border to be on a link of elem of the side
8643 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8644 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8645 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8646 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8647 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8649 insertMapIt = insertMap.find( elem );
8650 bool notFound = ( insertMapIt == insertMap.end() );
8651 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8653 // insert into another link of the same element:
8654 // 1. perform insertion into the other link of the elem
8655 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8656 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8657 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8658 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8659 // 2. perform insertion into the link of adjacent faces
8661 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8663 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8667 if (toCreatePolyedrs) {
8668 // perform insertion into the links of adjacent volumes
8669 UpdateVolumes(n12, n22, nodeList);
8671 // 3. find an element appeared on n1 and n2 after the insertion
8672 insertMap.erase( elem );
8673 elem = findAdjacentFace( n1, n2, 0 );
8675 if ( notFound || otherLink ) {
8676 // add element and nodes of the side into the insertMap
8677 insertMapIt = insertMap.insert
8678 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8679 (*insertMapIt).second.push_back( n1 );
8680 (*insertMapIt).second.push_back( n2 );
8682 // add node to be inserted into elem
8683 (*insertMapIt).second.push_back( nIns );
8684 next[ 1 - intoBord ] = true;
8687 // go to the next segment
8688 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8689 if ( next[ iBord ] ) {
8690 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8692 nPrev[ iBord ] = *nIt[ iBord ];
8693 nIt[ iBord ]++; i[ iBord ]++;
8697 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8699 // perform insertion of nodes into elements
8701 for (insertMapIt = insertMap.begin();
8702 insertMapIt != insertMap.end();
8705 const SMDS_MeshElement* elem = (*insertMapIt).first;
8706 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8707 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8708 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8710 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8712 if ( !theSideIsFreeBorder ) {
8713 // look for and insert nodes into the faces adjacent to elem
8715 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8717 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8722 if (toCreatePolyedrs) {
8723 // perform insertion into the links of adjacent volumes
8724 UpdateVolumes(n1, n2, nodeList);
8730 } // end: insert new nodes
8732 MergeNodes ( nodeGroupsToMerge );
8737 //=======================================================================
8738 //function : InsertNodesIntoLink
8739 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8740 // and theBetweenNode2 and split theElement
8741 //=======================================================================
8743 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8744 const SMDS_MeshNode* theBetweenNode1,
8745 const SMDS_MeshNode* theBetweenNode2,
8746 list<const SMDS_MeshNode*>& theNodesToInsert,
8747 const bool toCreatePoly)
8749 if ( theFace->GetType() != SMDSAbs_Face ) return;
8751 // find indices of 2 link nodes and of the rest nodes
8752 int iNode = 0, il1, il2, i3, i4;
8753 il1 = il2 = i3 = i4 = -1;
8754 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8755 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8757 if(theFace->IsQuadratic()) {
8758 const SMDS_VtkFace* F =
8759 dynamic_cast<const SMDS_VtkFace*>(theFace);
8760 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8761 // use special nodes iterator
8762 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8763 while( anIter->more() ) {
8764 const SMDS_MeshNode* n = cast2Node(anIter->next());
8765 if ( n == theBetweenNode1 )
8767 else if ( n == theBetweenNode2 )
8773 nodes[ iNode++ ] = n;
8777 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8778 while ( nodeIt->more() ) {
8779 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8780 if ( n == theBetweenNode1 )
8782 else if ( n == theBetweenNode2 )
8788 nodes[ iNode++ ] = n;
8791 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8794 // arrange link nodes to go one after another regarding the face orientation
8795 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8796 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8801 aNodesToInsert.reverse();
8803 // check that not link nodes of a quadrangles are in good order
8804 int nbFaceNodes = theFace->NbNodes();
8805 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8811 if (toCreatePoly || theFace->IsPoly()) {
8814 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8816 // add nodes of face up to first node of link
8819 if(theFace->IsQuadratic()) {
8820 const SMDS_VtkFace* F =
8821 dynamic_cast<const SMDS_VtkFace*>(theFace);
8822 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8823 // use special nodes iterator
8824 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8825 while( anIter->more() && !isFLN ) {
8826 const SMDS_MeshNode* n = cast2Node(anIter->next());
8827 poly_nodes[iNode++] = n;
8828 if (n == nodes[il1]) {
8832 // add nodes to insert
8833 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8834 for (; nIt != aNodesToInsert.end(); nIt++) {
8835 poly_nodes[iNode++] = *nIt;
8837 // add nodes of face starting from last node of link
8838 while ( anIter->more() ) {
8839 poly_nodes[iNode++] = cast2Node(anIter->next());
8843 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8844 while ( nodeIt->more() && !isFLN ) {
8845 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8846 poly_nodes[iNode++] = n;
8847 if (n == nodes[il1]) {
8851 // add nodes to insert
8852 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8853 for (; nIt != aNodesToInsert.end(); nIt++) {
8854 poly_nodes[iNode++] = *nIt;
8856 // add nodes of face starting from last node of link
8857 while ( nodeIt->more() ) {
8858 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8859 poly_nodes[iNode++] = n;
8863 // edit or replace the face
8864 SMESHDS_Mesh *aMesh = GetMeshDS();
8866 if (theFace->IsPoly()) {
8867 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8870 int aShapeId = FindShape( theFace );
8872 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8873 myLastCreatedElems.Append(newElem);
8874 if ( aShapeId && newElem )
8875 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8877 aMesh->RemoveElement(theFace);
8882 SMESHDS_Mesh *aMesh = GetMeshDS();
8883 if( !theFace->IsQuadratic() ) {
8885 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8886 int nbLinkNodes = 2 + aNodesToInsert.size();
8887 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8888 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8889 linkNodes[ 0 ] = nodes[ il1 ];
8890 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8891 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8892 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8893 linkNodes[ iNode++ ] = *nIt;
8895 // decide how to split a quadrangle: compare possible variants
8896 // and choose which of splits to be a quadrangle
8897 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8898 if ( nbFaceNodes == 3 ) {
8899 iBestQuad = nbSplits;
8902 else if ( nbFaceNodes == 4 ) {
8903 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8904 double aBestRate = DBL_MAX;
8905 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8907 double aBadRate = 0;
8908 // evaluate elements quality
8909 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8910 if ( iSplit == iQuad ) {
8911 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8915 aBadRate += getBadRate( &quad, aCrit );
8918 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8920 nodes[ iSplit < iQuad ? i4 : i3 ]);
8921 aBadRate += getBadRate( &tria, aCrit );
8925 if ( aBadRate < aBestRate ) {
8927 aBestRate = aBadRate;
8932 // create new elements
8933 int aShapeId = FindShape( theFace );
8936 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8937 SMDS_MeshElement* newElem = 0;
8938 if ( iSplit == iBestQuad )
8939 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8944 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8946 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8947 myLastCreatedElems.Append(newElem);
8948 if ( aShapeId && newElem )
8949 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8952 // change nodes of theFace
8953 const SMDS_MeshNode* newNodes[ 4 ];
8954 newNodes[ 0 ] = linkNodes[ i1 ];
8955 newNodes[ 1 ] = linkNodes[ i2 ];
8956 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8957 newNodes[ 3 ] = nodes[ i4 ];
8958 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8959 const SMDS_MeshElement* newElem = 0;
8960 if (iSplit == iBestQuad)
8961 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8963 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8964 myLastCreatedElems.Append(newElem);
8965 if ( aShapeId && newElem )
8966 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8967 } // end if(!theFace->IsQuadratic())
8968 else { // theFace is quadratic
8969 // we have to split theFace on simple triangles and one simple quadrangle
8971 int nbshift = tmp*2;
8972 // shift nodes in nodes[] by nbshift
8974 for(i=0; i<nbshift; i++) {
8975 const SMDS_MeshNode* n = nodes[0];
8976 for(j=0; j<nbFaceNodes-1; j++) {
8977 nodes[j] = nodes[j+1];
8979 nodes[nbFaceNodes-1] = n;
8981 il1 = il1 - nbshift;
8982 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8983 // n0 n1 n2 n0 n1 n2
8984 // +-----+-----+ +-----+-----+
8993 // create new elements
8994 int aShapeId = FindShape( theFace );
8997 if(nbFaceNodes==6) { // quadratic triangle
8998 SMDS_MeshElement* newElem =
8999 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9000 myLastCreatedElems.Append(newElem);
9001 if ( aShapeId && newElem )
9002 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9003 if(theFace->IsMediumNode(nodes[il1])) {
9004 // create quadrangle
9005 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9006 myLastCreatedElems.Append(newElem);
9007 if ( aShapeId && newElem )
9008 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9014 // create quadrangle
9015 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9016 myLastCreatedElems.Append(newElem);
9017 if ( aShapeId && newElem )
9018 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9024 else { // nbFaceNodes==8 - quadratic quadrangle
9025 SMDS_MeshElement* newElem =
9026 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9027 myLastCreatedElems.Append(newElem);
9028 if ( aShapeId && newElem )
9029 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9030 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9031 myLastCreatedElems.Append(newElem);
9032 if ( aShapeId && newElem )
9033 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9034 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9035 myLastCreatedElems.Append(newElem);
9036 if ( aShapeId && newElem )
9037 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9038 if(theFace->IsMediumNode(nodes[il1])) {
9039 // create quadrangle
9040 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9041 myLastCreatedElems.Append(newElem);
9042 if ( aShapeId && newElem )
9043 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9049 // create quadrangle
9050 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9051 myLastCreatedElems.Append(newElem);
9052 if ( aShapeId && newElem )
9053 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9059 // create needed triangles using n1,n2,n3 and inserted nodes
9060 int nbn = 2 + aNodesToInsert.size();
9061 //const SMDS_MeshNode* aNodes[nbn];
9062 vector<const SMDS_MeshNode*> aNodes(nbn);
9063 aNodes[0] = nodes[n1];
9064 aNodes[nbn-1] = nodes[n2];
9065 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9066 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9067 aNodes[iNode++] = *nIt;
9069 for(i=1; i<nbn; i++) {
9070 SMDS_MeshElement* newElem =
9071 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9072 myLastCreatedElems.Append(newElem);
9073 if ( aShapeId && newElem )
9074 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9078 aMesh->RemoveElement(theFace);
9081 //=======================================================================
9082 //function : UpdateVolumes
9084 //=======================================================================
9085 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9086 const SMDS_MeshNode* theBetweenNode2,
9087 list<const SMDS_MeshNode*>& theNodesToInsert)
9089 myLastCreatedElems.Clear();
9090 myLastCreatedNodes.Clear();
9092 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9093 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9094 const SMDS_MeshElement* elem = invElemIt->next();
9096 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9097 SMDS_VolumeTool aVolume (elem);
9098 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9101 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9102 int iface, nbFaces = aVolume.NbFaces();
9103 vector<const SMDS_MeshNode *> poly_nodes;
9104 vector<int> quantities (nbFaces);
9106 for (iface = 0; iface < nbFaces; iface++) {
9107 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9108 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9109 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9111 for (int inode = 0; inode < nbFaceNodes; inode++) {
9112 poly_nodes.push_back(faceNodes[inode]);
9114 if (nbInserted == 0) {
9115 if (faceNodes[inode] == theBetweenNode1) {
9116 if (faceNodes[inode + 1] == theBetweenNode2) {
9117 nbInserted = theNodesToInsert.size();
9119 // add nodes to insert
9120 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9121 for (; nIt != theNodesToInsert.end(); nIt++) {
9122 poly_nodes.push_back(*nIt);
9126 else if (faceNodes[inode] == theBetweenNode2) {
9127 if (faceNodes[inode + 1] == theBetweenNode1) {
9128 nbInserted = theNodesToInsert.size();
9130 // add nodes to insert in reversed order
9131 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9133 for (; nIt != theNodesToInsert.begin(); nIt--) {
9134 poly_nodes.push_back(*nIt);
9136 poly_nodes.push_back(*nIt);
9143 quantities[iface] = nbFaceNodes + nbInserted;
9146 // Replace or update the volume
9147 SMESHDS_Mesh *aMesh = GetMeshDS();
9149 if (elem->IsPoly()) {
9150 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9154 int aShapeId = FindShape( elem );
9156 SMDS_MeshElement* newElem =
9157 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9158 myLastCreatedElems.Append(newElem);
9159 if (aShapeId && newElem)
9160 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9162 aMesh->RemoveElement(elem);
9167 //=======================================================================
9169 * \brief Convert elements contained in a submesh to quadratic
9170 * \retval int - nb of checked elements
9172 //=======================================================================
9174 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9175 SMESH_MesherHelper& theHelper,
9176 const bool theForce3d)
9179 if( !theSm ) return nbElem;
9181 vector<int> nbNodeInFaces;
9182 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9183 while(ElemItr->more())
9186 const SMDS_MeshElement* elem = ElemItr->next();
9187 if( !elem || elem->IsQuadratic() ) continue;
9189 int id = elem->GetID();
9190 //MESSAGE("elem " << id);
9191 id = 0; // get a free number for new elements
9192 int nbNodes = elem->NbNodes();
9193 SMDSAbs_ElementType aType = elem->GetType();
9195 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9196 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9197 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9199 const SMDS_MeshElement* NewElem = 0;
9205 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9213 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9216 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9219 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9224 case SMDSAbs_Volume :
9229 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9232 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9235 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9238 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9239 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9242 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9249 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9251 theSm->AddElement( NewElem );
9253 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9255 // if (!GetMeshDS()->isCompacted())
9256 // GetMeshDS()->compactMesh();
9260 //=======================================================================
9261 //function : ConvertToQuadratic
9263 //=======================================================================
9264 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9266 SMESHDS_Mesh* meshDS = GetMeshDS();
9268 SMESH_MesherHelper aHelper(*myMesh);
9269 aHelper.SetIsQuadratic( true );
9271 int nbCheckedElems = 0;
9272 if ( myMesh->HasShapeToMesh() )
9274 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9276 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9277 while ( smIt->more() ) {
9278 SMESH_subMesh* sm = smIt->next();
9279 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9280 aHelper.SetSubShape( sm->GetSubShape() );
9281 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9286 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9287 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9289 SMESHDS_SubMesh *smDS = 0;
9290 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9291 while(aEdgeItr->more())
9293 const SMDS_MeshEdge* edge = aEdgeItr->next();
9294 if(edge && !edge->IsQuadratic())
9296 int id = edge->GetID();
9297 //MESSAGE("edge->GetID() " << id);
9298 const SMDS_MeshNode* n1 = edge->GetNode(0);
9299 const SMDS_MeshNode* n2 = edge->GetNode(1);
9301 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9303 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9304 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9307 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9308 while(aFaceItr->more())
9310 const SMDS_MeshFace* face = aFaceItr->next();
9311 if(!face || face->IsQuadratic() ) continue;
9313 int id = face->GetID();
9314 int nbNodes = face->NbNodes();
9315 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9317 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9319 SMDS_MeshFace * NewFace = 0;
9323 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9326 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9329 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9331 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9333 vector<int> nbNodeInFaces;
9334 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9335 while(aVolumeItr->more())
9337 const SMDS_MeshVolume* volume = aVolumeItr->next();
9338 if(!volume || volume->IsQuadratic() ) continue;
9340 int id = volume->GetID();
9341 int nbNodes = volume->NbNodes();
9342 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9343 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9344 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9346 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9348 SMDS_MeshVolume * NewVolume = 0;
9352 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9353 nodes[3], id, theForce3d );
9356 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9357 nodes[3], nodes[4], id, theForce3d);
9360 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9361 nodes[3], nodes[4], nodes[5], id, theForce3d);
9364 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9365 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9368 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9370 ReplaceElemInGroups(volume, NewVolume, meshDS);
9374 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9375 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9376 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9377 aHelper.FixQuadraticElements();
9379 if (!GetMeshDS()->isCompacted())
9380 GetMeshDS()->compactMesh();
9383 //=======================================================================
9385 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9386 * \retval int - nb of checked elements
9388 //=======================================================================
9390 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9391 SMDS_ElemIteratorPtr theItr,
9392 const int theShapeID)
9395 SMESHDS_Mesh* meshDS = GetMeshDS();
9396 const bool notFromGroups = false;
9398 while( theItr->more() )
9400 const SMDS_MeshElement* elem = theItr->next();
9402 if( elem && elem->IsQuadratic())
9404 int id = elem->GetID();
9405 int nbNodes = elem->NbNodes();
9406 vector<const SMDS_MeshNode *> nodes, mediumNodes;
9407 nodes.reserve( nbNodes );
9408 mediumNodes.reserve( nbNodes );
9410 for(int i = 0; i < nbNodes; i++)
9412 const SMDS_MeshNode* n = elem->GetNode(i);
9414 if( elem->IsMediumNode( n ) )
9415 mediumNodes.push_back( n );
9417 nodes.push_back( n );
9419 if( nodes.empty() ) continue;
9420 SMDSAbs_ElementType aType = elem->GetType();
9422 //remove old quadratic element
9423 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9425 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9426 ReplaceElemInGroups(elem, NewElem, meshDS);
9427 if( theSm && NewElem )
9428 theSm->AddElement( NewElem );
9430 // remove medium nodes
9431 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9432 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9433 const SMDS_MeshNode* n = *nIt;
9434 if ( n->NbInverseElements() == 0 ) {
9435 if ( n->getshapeId() != theShapeID )
9436 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9437 ( n->getshapeId() ));
9439 meshDS->RemoveFreeNode( n, theSm );
9447 //=======================================================================
9448 //function : ConvertFromQuadratic
9450 //=======================================================================
9451 bool SMESH_MeshEditor::ConvertFromQuadratic()
9453 int nbCheckedElems = 0;
9454 if ( myMesh->HasShapeToMesh() )
9456 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9458 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9459 while ( smIt->more() ) {
9460 SMESH_subMesh* sm = smIt->next();
9461 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9462 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9468 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9469 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9471 SMESHDS_SubMesh *aSM = 0;
9472 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9478 //=======================================================================
9479 //function : SewSideElements
9481 //=======================================================================
9483 SMESH_MeshEditor::Sew_Error
9484 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9485 TIDSortedElemSet& theSide2,
9486 const SMDS_MeshNode* theFirstNode1,
9487 const SMDS_MeshNode* theFirstNode2,
9488 const SMDS_MeshNode* theSecondNode1,
9489 const SMDS_MeshNode* theSecondNode2)
9491 myLastCreatedElems.Clear();
9492 myLastCreatedNodes.Clear();
9494 MESSAGE ("::::SewSideElements()");
9495 if ( theSide1.size() != theSide2.size() )
9496 return SEW_DIFF_NB_OF_ELEMENTS;
9498 Sew_Error aResult = SEW_OK;
9500 // 1. Build set of faces representing each side
9501 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9502 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9504 // =======================================================================
9505 // 1. Build set of faces representing each side:
9506 // =======================================================================
9507 // a. build set of nodes belonging to faces
9508 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9509 // c. create temporary faces representing side of volumes if correspondent
9510 // face does not exist
9512 SMESHDS_Mesh* aMesh = GetMeshDS();
9513 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9514 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9515 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9516 set<const SMDS_MeshElement*> volSet1, volSet2;
9517 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9518 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9519 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9520 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9521 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9522 int iSide, iFace, iNode;
9524 list<const SMDS_MeshElement* > tempFaceList;
9525 for ( iSide = 0; iSide < 2; iSide++ ) {
9526 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9527 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9528 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9529 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9530 set<const SMDS_MeshElement*>::iterator vIt;
9531 TIDSortedElemSet::iterator eIt;
9532 set<const SMDS_MeshNode*>::iterator nIt;
9534 // check that given nodes belong to given elements
9535 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9536 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9537 int firstIndex = -1, secondIndex = -1;
9538 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9539 const SMDS_MeshElement* elem = *eIt;
9540 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9541 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9542 if ( firstIndex > -1 && secondIndex > -1 ) break;
9544 if ( firstIndex < 0 || secondIndex < 0 ) {
9545 // we can simply return until temporary faces created
9546 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9549 // -----------------------------------------------------------
9550 // 1a. Collect nodes of existing faces
9551 // and build set of face nodes in order to detect missing
9552 // faces corresponding to sides of volumes
9553 // -----------------------------------------------------------
9555 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9557 // loop on the given element of a side
9558 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9559 //const SMDS_MeshElement* elem = *eIt;
9560 const SMDS_MeshElement* elem = *eIt;
9561 if ( elem->GetType() == SMDSAbs_Face ) {
9562 faceSet->insert( elem );
9563 set <const SMDS_MeshNode*> faceNodeSet;
9564 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9565 while ( nodeIt->more() ) {
9566 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9567 nodeSet->insert( n );
9568 faceNodeSet.insert( n );
9570 setOfFaceNodeSet.insert( faceNodeSet );
9572 else if ( elem->GetType() == SMDSAbs_Volume )
9573 volSet->insert( elem );
9575 // ------------------------------------------------------------------------------
9576 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9577 // ------------------------------------------------------------------------------
9579 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9580 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9581 while ( fIt->more() ) { // loop on faces sharing a node
9582 const SMDS_MeshElement* f = fIt->next();
9583 if ( faceSet->find( f ) == faceSet->end() ) {
9584 // check if all nodes are in nodeSet and
9585 // complete setOfFaceNodeSet if they are
9586 set <const SMDS_MeshNode*> faceNodeSet;
9587 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9588 bool allInSet = true;
9589 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9590 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9591 if ( nodeSet->find( n ) == nodeSet->end() )
9594 faceNodeSet.insert( n );
9597 faceSet->insert( f );
9598 setOfFaceNodeSet.insert( faceNodeSet );
9604 // -------------------------------------------------------------------------
9605 // 1c. Create temporary faces representing sides of volumes if correspondent
9606 // face does not exist
9607 // -------------------------------------------------------------------------
9609 if ( !volSet->empty() ) {
9610 //int nodeSetSize = nodeSet->size();
9612 // loop on given volumes
9613 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9614 SMDS_VolumeTool vol (*vIt);
9615 // loop on volume faces: find free faces
9616 // --------------------------------------
9617 list<const SMDS_MeshElement* > freeFaceList;
9618 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9619 if ( !vol.IsFreeFace( iFace ))
9621 // check if there is already a face with same nodes in a face set
9622 const SMDS_MeshElement* aFreeFace = 0;
9623 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9624 int nbNodes = vol.NbFaceNodes( iFace );
9625 set <const SMDS_MeshNode*> faceNodeSet;
9626 vol.GetFaceNodes( iFace, faceNodeSet );
9627 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9629 // no such a face is given but it still can exist, check it
9630 if ( nbNodes == 3 ) {
9631 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9633 else if ( nbNodes == 4 ) {
9634 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9637 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9638 aFreeFace = aMesh->FindFace(poly_nodes);
9642 // create a temporary face
9643 if ( nbNodes == 3 ) {
9644 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9645 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9647 else if ( nbNodes == 4 ) {
9648 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9649 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9652 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9653 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9654 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9658 freeFaceList.push_back( aFreeFace );
9659 tempFaceList.push_back( aFreeFace );
9662 } // loop on faces of a volume
9664 // choose one of several free faces
9665 // --------------------------------------
9666 if ( freeFaceList.size() > 1 ) {
9667 // choose a face having max nb of nodes shared by other elems of a side
9668 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9669 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9670 while ( fIt != freeFaceList.end() ) { // loop on free faces
9671 int nbSharedNodes = 0;
9672 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9673 while ( nodeIt->more() ) { // loop on free face nodes
9674 const SMDS_MeshNode* n =
9675 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9676 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9677 while ( invElemIt->more() ) {
9678 const SMDS_MeshElement* e = invElemIt->next();
9679 if ( faceSet->find( e ) != faceSet->end() )
9681 if ( elemSet->find( e ) != elemSet->end() )
9685 if ( nbSharedNodes >= maxNbNodes ) {
9686 maxNbNodes = nbSharedNodes;
9690 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9692 if ( freeFaceList.size() > 1 )
9694 // could not choose one face, use another way
9695 // choose a face most close to the bary center of the opposite side
9696 gp_XYZ aBC( 0., 0., 0. );
9697 set <const SMDS_MeshNode*> addedNodes;
9698 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9699 eIt = elemSet2->begin();
9700 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9701 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9702 while ( nodeIt->more() ) { // loop on free face nodes
9703 const SMDS_MeshNode* n =
9704 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9705 if ( addedNodes.insert( n ).second )
9706 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9709 aBC /= addedNodes.size();
9710 double minDist = DBL_MAX;
9711 fIt = freeFaceList.begin();
9712 while ( fIt != freeFaceList.end() ) { // loop on free faces
9714 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9715 while ( nodeIt->more() ) { // loop on free face nodes
9716 const SMDS_MeshNode* n =
9717 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9718 gp_XYZ p( n->X(),n->Y(),n->Z() );
9719 dist += ( aBC - p ).SquareModulus();
9721 if ( dist < minDist ) {
9723 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9726 fIt = freeFaceList.erase( fIt++ );
9729 } // choose one of several free faces of a volume
9731 if ( freeFaceList.size() == 1 ) {
9732 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9733 faceSet->insert( aFreeFace );
9734 // complete a node set with nodes of a found free face
9735 // for ( iNode = 0; iNode < ; iNode++ )
9736 // nodeSet->insert( fNodes[ iNode ] );
9739 } // loop on volumes of a side
9741 // // complete a set of faces if new nodes in a nodeSet appeared
9742 // // ----------------------------------------------------------
9743 // if ( nodeSetSize != nodeSet->size() ) {
9744 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9745 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9746 // while ( fIt->more() ) { // loop on faces sharing a node
9747 // const SMDS_MeshElement* f = fIt->next();
9748 // if ( faceSet->find( f ) == faceSet->end() ) {
9749 // // check if all nodes are in nodeSet and
9750 // // complete setOfFaceNodeSet if they are
9751 // set <const SMDS_MeshNode*> faceNodeSet;
9752 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9753 // bool allInSet = true;
9754 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9755 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9756 // if ( nodeSet->find( n ) == nodeSet->end() )
9757 // allInSet = false;
9759 // faceNodeSet.insert( n );
9761 // if ( allInSet ) {
9762 // faceSet->insert( f );
9763 // setOfFaceNodeSet.insert( faceNodeSet );
9769 } // Create temporary faces, if there are volumes given
9772 if ( faceSet1.size() != faceSet2.size() ) {
9773 // delete temporary faces: they are in reverseElements of actual nodes
9774 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9775 // while ( tmpFaceIt->more() )
9776 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9777 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9778 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9779 // aMesh->RemoveElement(*tmpFaceIt);
9780 MESSAGE("Diff nb of faces");
9781 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9784 // ============================================================
9785 // 2. Find nodes to merge:
9786 // bind a node to remove to a node to put instead
9787 // ============================================================
9789 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9790 if ( theFirstNode1 != theFirstNode2 )
9791 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9792 if ( theSecondNode1 != theSecondNode2 )
9793 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9795 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9796 set< long > linkIdSet; // links to process
9797 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9799 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9800 list< NLink > linkList[2];
9801 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9802 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9803 // loop on links in linkList; find faces by links and append links
9804 // of the found faces to linkList
9805 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9806 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9807 NLink link[] = { *linkIt[0], *linkIt[1] };
9808 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9809 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9812 // by links, find faces in the face sets,
9813 // and find indices of link nodes in the found faces;
9814 // in a face set, there is only one or no face sharing a link
9815 // ---------------------------------------------------------------
9817 const SMDS_MeshElement* face[] = { 0, 0 };
9818 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9819 vector<const SMDS_MeshNode*> fnodes1(9);
9820 vector<const SMDS_MeshNode*> fnodes2(9);
9821 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9822 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9823 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9824 int iLinkNode[2][2];
9825 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9826 const SMDS_MeshNode* n1 = link[iSide].first;
9827 const SMDS_MeshNode* n2 = link[iSide].second;
9828 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9829 set< const SMDS_MeshElement* > fMap;
9830 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9831 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9832 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9833 while ( fIt->more() ) { // loop on faces sharing a node
9834 const SMDS_MeshElement* f = fIt->next();
9835 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9836 ! fMap.insert( f ).second ) // f encounters twice
9838 if ( face[ iSide ] ) {
9839 MESSAGE( "2 faces per link " );
9840 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9844 faceSet->erase( f );
9845 // get face nodes and find ones of a link
9850 fnodes1.resize(f->NbNodes()+1);
9851 notLinkNodes1.resize(f->NbNodes()-2);
9854 fnodes2.resize(f->NbNodes()+1);
9855 notLinkNodes2.resize(f->NbNodes()-2);
9858 if(!f->IsQuadratic()) {
9859 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9860 while ( nIt->more() ) {
9861 const SMDS_MeshNode* n =
9862 static_cast<const SMDS_MeshNode*>( nIt->next() );
9864 iLinkNode[ iSide ][ 0 ] = iNode;
9866 else if ( n == n2 ) {
9867 iLinkNode[ iSide ][ 1 ] = iNode;
9869 //else if ( notLinkNodes[ iSide ][ 0 ] )
9870 // notLinkNodes[ iSide ][ 1 ] = n;
9872 // notLinkNodes[ iSide ][ 0 ] = n;
9876 notLinkNodes1[nbl] = n;
9877 //notLinkNodes1.push_back(n);
9879 notLinkNodes2[nbl] = n;
9880 //notLinkNodes2.push_back(n);
9882 //faceNodes[ iSide ][ iNode++ ] = n;
9884 fnodes1[iNode++] = n;
9887 fnodes2[iNode++] = n;
9891 else { // f->IsQuadratic()
9892 const SMDS_VtkFace* F =
9893 dynamic_cast<const SMDS_VtkFace*>(f);
9894 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9895 // use special nodes iterator
9896 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9897 while ( anIter->more() ) {
9898 const SMDS_MeshNode* n =
9899 static_cast<const SMDS_MeshNode*>( anIter->next() );
9901 iLinkNode[ iSide ][ 0 ] = iNode;
9903 else if ( n == n2 ) {
9904 iLinkNode[ iSide ][ 1 ] = iNode;
9909 notLinkNodes1[nbl] = n;
9912 notLinkNodes2[nbl] = n;
9916 fnodes1[iNode++] = n;
9919 fnodes2[iNode++] = n;
9923 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9925 fnodes1[iNode] = fnodes1[0];
9928 fnodes2[iNode] = fnodes1[0];
9935 // check similarity of elements of the sides
9936 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9937 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9938 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9939 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9942 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9944 break; // do not return because it s necessary to remove tmp faces
9947 // set nodes to merge
9948 // -------------------
9950 if ( face[0] && face[1] ) {
9951 int nbNodes = face[0]->NbNodes();
9952 if ( nbNodes != face[1]->NbNodes() ) {
9953 MESSAGE("Diff nb of face nodes");
9954 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9955 break; // do not return because it s necessary to remove tmp faces
9957 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9958 if ( nbNodes == 3 ) {
9959 //nReplaceMap.insert( TNodeNodeMap::value_type
9960 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9961 nReplaceMap.insert( TNodeNodeMap::value_type
9962 ( notLinkNodes1[0], notLinkNodes2[0] ));
9965 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9966 // analyse link orientation in faces
9967 int i1 = iLinkNode[ iSide ][ 0 ];
9968 int i2 = iLinkNode[ iSide ][ 1 ];
9969 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9970 // if notLinkNodes are the first and the last ones, then
9971 // their order does not correspond to the link orientation
9972 if (( i1 == 1 && i2 == 2 ) ||
9973 ( i1 == 2 && i2 == 1 ))
9974 reverse[ iSide ] = !reverse[ iSide ];
9976 if ( reverse[0] == reverse[1] ) {
9977 //nReplaceMap.insert( TNodeNodeMap::value_type
9978 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9979 //nReplaceMap.insert( TNodeNodeMap::value_type
9980 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9981 for(int nn=0; nn<nbNodes-2; nn++) {
9982 nReplaceMap.insert( TNodeNodeMap::value_type
9983 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9987 //nReplaceMap.insert( TNodeNodeMap::value_type
9988 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9989 //nReplaceMap.insert( TNodeNodeMap::value_type
9990 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9991 for(int nn=0; nn<nbNodes-2; nn++) {
9992 nReplaceMap.insert( TNodeNodeMap::value_type
9993 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9998 // add other links of the faces to linkList
9999 // -----------------------------------------
10001 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10002 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10003 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10004 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10005 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10006 if ( !iter_isnew.second ) { // already in a set: no need to process
10007 linkIdSet.erase( iter_isnew.first );
10009 else // new in set == encountered for the first time: add
10011 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10012 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10013 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10014 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10015 linkList[0].push_back ( NLink( n1, n2 ));
10016 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10020 } // loop on link lists
10022 if ( aResult == SEW_OK &&
10023 ( linkIt[0] != linkList[0].end() ||
10024 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10025 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10026 " " << (faceSetPtr[1]->empty()));
10027 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10030 // ====================================================================
10031 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10032 // ====================================================================
10034 // delete temporary faces: they are in reverseElements of actual nodes
10035 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10036 // while ( tmpFaceIt->more() )
10037 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10038 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10039 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10040 // aMesh->RemoveElement(*tmpFaceIt);
10042 if ( aResult != SEW_OK)
10045 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10046 // loop on nodes replacement map
10047 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10048 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10049 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10050 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10051 nodeIDsToRemove.push_back( nToRemove->GetID() );
10052 // loop on elements sharing nToRemove
10053 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10054 while ( invElemIt->more() ) {
10055 const SMDS_MeshElement* e = invElemIt->next();
10056 // get a new suite of nodes: make replacement
10057 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10058 vector< const SMDS_MeshNode*> nodes( nbNodes );
10059 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10060 while ( nIt->more() ) {
10061 const SMDS_MeshNode* n =
10062 static_cast<const SMDS_MeshNode*>( nIt->next() );
10063 nnIt = nReplaceMap.find( n );
10064 if ( nnIt != nReplaceMap.end() ) {
10066 n = (*nnIt).second;
10070 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10071 // elemIDsToRemove.push_back( e->GetID() );
10075 SMDSAbs_ElementType etyp = e->GetType();
10076 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10079 myLastCreatedElems.Append(newElem);
10080 AddToSameGroups(newElem, e, aMesh);
10081 int aShapeId = e->getshapeId();
10084 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10087 aMesh->RemoveElement(e);
10092 Remove( nodeIDsToRemove, true );
10097 //================================================================================
10099 * \brief Find corresponding nodes in two sets of faces
10100 * \param theSide1 - first face set
10101 * \param theSide2 - second first face
10102 * \param theFirstNode1 - a boundary node of set 1
10103 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10104 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10105 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10106 * \param nReplaceMap - output map of corresponding nodes
10107 * \retval bool - is a success or not
10109 //================================================================================
10112 //#define DEBUG_MATCHING_NODES
10115 SMESH_MeshEditor::Sew_Error
10116 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10117 set<const SMDS_MeshElement*>& theSide2,
10118 const SMDS_MeshNode* theFirstNode1,
10119 const SMDS_MeshNode* theFirstNode2,
10120 const SMDS_MeshNode* theSecondNode1,
10121 const SMDS_MeshNode* theSecondNode2,
10122 TNodeNodeMap & nReplaceMap)
10124 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10126 nReplaceMap.clear();
10127 if ( theFirstNode1 != theFirstNode2 )
10128 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10129 if ( theSecondNode1 != theSecondNode2 )
10130 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10132 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10133 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10135 list< NLink > linkList[2];
10136 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10137 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10139 // loop on links in linkList; find faces by links and append links
10140 // of the found faces to linkList
10141 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10142 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10143 NLink link[] = { *linkIt[0], *linkIt[1] };
10144 if ( linkSet.find( link[0] ) == linkSet.end() )
10147 // by links, find faces in the face sets,
10148 // and find indices of link nodes in the found faces;
10149 // in a face set, there is only one or no face sharing a link
10150 // ---------------------------------------------------------------
10152 const SMDS_MeshElement* face[] = { 0, 0 };
10153 list<const SMDS_MeshNode*> notLinkNodes[2];
10154 //bool reverse[] = { false, false }; // order of notLinkNodes
10156 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10158 const SMDS_MeshNode* n1 = link[iSide].first;
10159 const SMDS_MeshNode* n2 = link[iSide].second;
10160 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10161 set< const SMDS_MeshElement* > facesOfNode1;
10162 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10164 // during a loop of the first node, we find all faces around n1,
10165 // during a loop of the second node, we find one face sharing both n1 and n2
10166 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10167 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10168 while ( fIt->more() ) { // loop on faces sharing a node
10169 const SMDS_MeshElement* f = fIt->next();
10170 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10171 ! facesOfNode1.insert( f ).second ) // f encounters twice
10173 if ( face[ iSide ] ) {
10174 MESSAGE( "2 faces per link " );
10175 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10178 faceSet->erase( f );
10180 // get not link nodes
10181 int nbN = f->NbNodes();
10182 if ( f->IsQuadratic() )
10184 nbNodes[ iSide ] = nbN;
10185 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10186 int i1 = f->GetNodeIndex( n1 );
10187 int i2 = f->GetNodeIndex( n2 );
10188 int iEnd = nbN, iBeg = -1, iDelta = 1;
10189 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10191 std::swap( iEnd, iBeg ); iDelta = -1;
10196 if ( i == iEnd ) i = iBeg + iDelta;
10197 if ( i == i1 ) break;
10198 nodes.push_back ( f->GetNode( i ) );
10204 // check similarity of elements of the sides
10205 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10206 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10207 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10208 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10211 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10215 // set nodes to merge
10216 // -------------------
10218 if ( face[0] && face[1] ) {
10219 if ( nbNodes[0] != nbNodes[1] ) {
10220 MESSAGE("Diff nb of face nodes");
10221 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10223 #ifdef DEBUG_MATCHING_NODES
10224 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10225 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10226 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10228 int nbN = nbNodes[0];
10230 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10231 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10232 for ( int i = 0 ; i < nbN - 2; ++i ) {
10233 #ifdef DEBUG_MATCHING_NODES
10234 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10236 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10240 // add other links of the face 1 to linkList
10241 // -----------------------------------------
10243 const SMDS_MeshElement* f0 = face[0];
10244 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10245 for ( int i = 0; i < nbN; i++ )
10247 const SMDS_MeshNode* n2 = f0->GetNode( i );
10248 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10249 linkSet.insert( SMESH_TLink( n1, n2 ));
10250 if ( !iter_isnew.second ) { // already in a set: no need to process
10251 linkSet.erase( iter_isnew.first );
10253 else // new in set == encountered for the first time: add
10255 #ifdef DEBUG_MATCHING_NODES
10256 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10257 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10259 linkList[0].push_back ( NLink( n1, n2 ));
10260 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10265 } // loop on link lists
10270 //================================================================================
10272 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10273 \param theElems - the list of elements (edges or faces) to be replicated
10274 The nodes for duplication could be found from these elements
10275 \param theNodesNot - list of nodes to NOT replicate
10276 \param theAffectedElems - the list of elements (cells and edges) to which the
10277 replicated nodes should be associated to.
10278 \return TRUE if operation has been completed successfully, FALSE otherwise
10280 //================================================================================
10282 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10283 const TIDSortedElemSet& theNodesNot,
10284 const TIDSortedElemSet& theAffectedElems )
10286 myLastCreatedElems.Clear();
10287 myLastCreatedNodes.Clear();
10289 if ( theElems.size() == 0 )
10292 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10297 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10298 // duplicate elements and nodes
10299 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10300 // replce nodes by duplications
10301 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10305 //================================================================================
10307 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10308 \param theMeshDS - mesh instance
10309 \param theElems - the elements replicated or modified (nodes should be changed)
10310 \param theNodesNot - nodes to NOT replicate
10311 \param theNodeNodeMap - relation of old node to new created node
10312 \param theIsDoubleElem - flag os to replicate element or modify
10313 \return TRUE if operation has been completed successfully, FALSE otherwise
10315 //================================================================================
10317 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10318 const TIDSortedElemSet& theElems,
10319 const TIDSortedElemSet& theNodesNot,
10320 std::map< const SMDS_MeshNode*,
10321 const SMDS_MeshNode* >& theNodeNodeMap,
10322 const bool theIsDoubleElem )
10324 MESSAGE("doubleNodes");
10325 // iterate on through element and duplicate them (by nodes duplication)
10327 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10328 for ( ; elemItr != theElems.end(); ++elemItr )
10330 const SMDS_MeshElement* anElem = *elemItr;
10334 bool isDuplicate = false;
10335 // duplicate nodes to duplicate element
10336 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10337 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10339 while ( anIter->more() )
10342 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10343 SMDS_MeshNode* aNewNode = aCurrNode;
10344 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10345 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10346 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10349 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10350 theNodeNodeMap[ aCurrNode ] = aNewNode;
10351 myLastCreatedNodes.Append( aNewNode );
10353 isDuplicate |= (aCurrNode != aNewNode);
10354 newNodes[ ind++ ] = aNewNode;
10356 if ( !isDuplicate )
10359 if ( theIsDoubleElem )
10360 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10363 MESSAGE("ChangeElementNodes");
10364 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10371 //================================================================================
10373 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10374 \param theNodes - identifiers of nodes to be doubled
10375 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10376 nodes. If list of element identifiers is empty then nodes are doubled but
10377 they not assigned to elements
10378 \return TRUE if operation has been completed successfully, FALSE otherwise
10380 //================================================================================
10382 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10383 const std::list< int >& theListOfModifiedElems )
10385 MESSAGE("DoubleNodes");
10386 myLastCreatedElems.Clear();
10387 myLastCreatedNodes.Clear();
10389 if ( theListOfNodes.size() == 0 )
10392 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10396 // iterate through nodes and duplicate them
10398 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10400 std::list< int >::const_iterator aNodeIter;
10401 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10403 int aCurr = *aNodeIter;
10404 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10410 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10413 anOldNodeToNewNode[ aNode ] = aNewNode;
10414 myLastCreatedNodes.Append( aNewNode );
10418 // Create map of new nodes for modified elements
10420 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10422 std::list< int >::const_iterator anElemIter;
10423 for ( anElemIter = theListOfModifiedElems.begin();
10424 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10426 int aCurr = *anElemIter;
10427 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10431 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10433 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10435 while ( anIter->more() )
10437 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10438 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10440 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10441 aNodeArr[ ind++ ] = aNewNode;
10444 aNodeArr[ ind++ ] = aCurrNode;
10446 anElemToNodes[ anElem ] = aNodeArr;
10449 // Change nodes of elements
10451 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10452 anElemToNodesIter = anElemToNodes.begin();
10453 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10455 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10456 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10459 MESSAGE("ChangeElementNodes");
10460 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10469 //================================================================================
10471 \brief Check if element located inside shape
10472 \return TRUE if IN or ON shape, FALSE otherwise
10474 //================================================================================
10476 template<class Classifier>
10477 bool isInside(const SMDS_MeshElement* theElem,
10478 Classifier& theClassifier,
10479 const double theTol)
10481 gp_XYZ centerXYZ (0, 0, 0);
10482 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10483 while (aNodeItr->more())
10484 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10486 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10487 theClassifier.Perform(aPnt, theTol);
10488 TopAbs_State aState = theClassifier.State();
10489 return (aState == TopAbs_IN || aState == TopAbs_ON );
10492 //================================================================================
10494 * \brief Classifier of the 3D point on the TopoDS_Face
10495 * with interaface suitable for isInside()
10497 //================================================================================
10499 struct _FaceClassifier
10501 Extrema_ExtPS _extremum;
10502 BRepAdaptor_Surface _surface;
10503 TopAbs_State _state;
10505 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10507 _extremum.Initialize( _surface,
10508 _surface.FirstUParameter(), _surface.LastUParameter(),
10509 _surface.FirstVParameter(), _surface.LastVParameter(),
10510 _surface.Tolerance(), _surface.Tolerance() );
10512 void Perform(const gp_Pnt& aPnt, double theTol)
10514 _state = TopAbs_OUT;
10515 _extremum.Perform(aPnt);
10516 if ( _extremum.IsDone() )
10517 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10518 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10520 TopAbs_State State() const
10527 //================================================================================
10529 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10530 \param theElems - group of of elements (edges or faces) to be replicated
10531 \param theNodesNot - group of nodes not to replicate
10532 \param theShape - shape to detect affected elements (element which geometric center
10533 located on or inside shape).
10534 The replicated nodes should be associated to affected elements.
10535 \return TRUE if operation has been completed successfully, FALSE otherwise
10537 //================================================================================
10539 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10540 const TIDSortedElemSet& theNodesNot,
10541 const TopoDS_Shape& theShape )
10543 if ( theShape.IsNull() )
10546 const double aTol = Precision::Confusion();
10547 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10548 auto_ptr<_FaceClassifier> aFaceClassifier;
10549 if ( theShape.ShapeType() == TopAbs_SOLID )
10551 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10552 bsc3d->PerformInfinitePoint(aTol);
10554 else if (theShape.ShapeType() == TopAbs_FACE )
10556 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10559 // iterates on indicated elements and get elements by back references from their nodes
10560 TIDSortedElemSet anAffected;
10561 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10562 for ( ; elemItr != theElems.end(); ++elemItr )
10564 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10568 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10569 while ( nodeItr->more() )
10571 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10572 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10574 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10575 while ( backElemItr->more() )
10577 const SMDS_MeshElement* curElem = backElemItr->next();
10578 if ( curElem && theElems.find(curElem) == theElems.end() &&
10580 isInside( curElem, *bsc3d, aTol ) :
10581 isInside( curElem, *aFaceClassifier, aTol )))
10582 anAffected.insert( curElem );
10586 return DoubleNodes( theElems, theNodesNot, anAffected );
10590 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10591 * The list of groups must describe a partition of the mesh volumes.
10592 * The nodes of the internal faces at the boundaries of the groups are doubled.
10593 * In option, the internal faces are replaced by flat elements.
10594 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10595 * @param theElems - list of groups of volumes, where a group of volume is a set of
10596 * SMDS_MeshElements sorted by Id.
10597 * @param createJointElems - if TRUE, create the elements
10598 * @return TRUE if operation has been completed successfully, FALSE otherwise
10600 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10601 bool createJointElems)
10603 MESSAGE("------------------------------------------------------");
10604 MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10605 MESSAGE("------------------------------------------------------");
10607 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10608 meshDS->BuildDownWardConnectivity(false);
10610 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10612 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10613 // build the list of nodes shared by 2 or more domains, with their domain indexes
10615 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10616 std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
10617 faceDomains.clear();
10618 nodeDomains.clear();
10619 std::map<int,int> emptyMap;
10622 for (int idom = 0; idom < theElems.size(); idom++)
10625 // --- build a map (face to duplicate --> volume to modify)
10626 // with all the faces shared by 2 domains (group of elements)
10627 // and corresponding volume of this domain, for each shared face.
10628 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10630 const TIDSortedElemSet& domain = theElems[idom];
10631 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10632 for (; elemItr != domain.end(); ++elemItr)
10634 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10637 int vtkId = anElem->getVtkId();
10638 int neighborsVtkIds[NBMAXNEIGHBORS];
10639 int downIds[NBMAXNEIGHBORS];
10640 unsigned char downTypes[NBMAXNEIGHBORS];
10641 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10642 for (int n = 0; n < nbNeighbors; n++)
10644 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10645 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10646 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10648 DownIdType face(downIds[n], downTypes[n]);
10649 if (!faceDomains.count(face))
10650 faceDomains[face] = emptyMap; // create an empty entry for face
10651 if (!faceDomains[face].count(idom))
10653 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10660 MESSAGE("Number of shared faces " << faceDomains.size());
10662 // --- for each shared face, get the nodes
10663 // for each node, for each domain of the face, create a clone of the node
10665 std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10666 for( ; itface != faceDomains.end();++itface )
10668 DownIdType face = itface->first;
10669 std::map<int,int> domvol = itface->second;
10670 std::set<int> oldNodes;
10672 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10673 std::set<int>::iterator itn = oldNodes.begin();
10674 for (;itn != oldNodes.end(); ++itn)
10677 if (!nodeDomains.count(oldId))
10678 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10679 std::map<int,int>::iterator itdom = domvol.begin();
10680 for(; itdom != domvol.end(); ++itdom)
10682 int idom = itdom->first;
10683 if ( nodeDomains[oldId].empty() )
10684 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10687 double *coords = grid->GetPoint(oldId);
10688 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10689 int newId = newNode->getVtkId();
10690 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10696 // --- iterate on shared faces (volumes to modify, face to extrude)
10697 // get node id's of the face (id SMDS = id VTK)
10698 // create flat element with old and new nodes if requested
10700 if (createJointElems)
10702 itface = faceDomains.begin();
10703 for( ; itface != faceDomains.end();++itface )
10705 DownIdType face = itface->first;
10706 std::set<int> oldNodes;
10707 std::set<int>::iterator itn;
10709 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10710 std::map<int,int> localClonedNodeIds;
10712 std::map<int,int> domvol = itface->second;
10713 std::map<int,int>::iterator itdom = domvol.begin();
10714 int dom1 = itdom->first;
10715 int vtkVolId = itdom->second;
10717 int dom2 = itdom->first;
10719 localClonedNodeIds.clear();
10720 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10724 if (nodeDomains[oldId].count(dom1))
10725 refid = nodeDomains[oldId][dom1];
10727 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10729 if (nodeDomains[oldId].count(dom2))
10730 newid = nodeDomains[oldId][dom2];
10732 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10733 localClonedNodeIds[oldId] = newid;
10735 meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10739 // --- iterate on shared faces (volumes to modify, face to extrude)
10740 // get node id's of the face
10741 // replace old nodes by new nodes in volumes, and update inverse connectivity
10743 itface = faceDomains.begin();
10744 for( ; itface != faceDomains.end();++itface )
10746 DownIdType face = itface->first;
10747 std::set<int> oldNodes;
10748 std::set<int>::iterator itn;
10750 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10751 std::map<int,int> localClonedNodeIds;
10753 std::map<int,int> domvol = itface->second;
10754 std::map<int,int>::iterator itdom = domvol.begin();
10755 for(; itdom != domvol.end(); ++itdom)
10757 int idom = itdom->first;
10758 int vtkVolId = itdom->second;
10759 localClonedNodeIds.clear();
10760 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10763 if (nodeDomains[oldId].count(idom))
10764 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10766 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10769 grid->BuildLinks();
10771 // TODO replace also old nodes by new nodes in faces and edges
10777 //================================================================================
10779 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10780 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10781 * \return TRUE if operation has been completed successfully, FALSE otherwise
10783 //================================================================================
10785 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10787 // iterates on volume elements and detect all free faces on them
10788 SMESHDS_Mesh* aMesh = GetMeshDS();
10791 //bool res = false;
10792 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10793 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10796 const SMDS_MeshVolume* volume = vIt->next();
10797 SMDS_VolumeTool vTool( volume );
10798 vTool.SetExternalNormal();
10799 const bool isPoly = volume->IsPoly();
10800 const bool isQuad = volume->IsQuadratic();
10801 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10803 if (!vTool.IsFreeFace(iface))
10806 vector<const SMDS_MeshNode *> nodes;
10807 int nbFaceNodes = vTool.NbFaceNodes(iface);
10808 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10810 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10811 nodes.push_back(faceNodes[inode]);
10813 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10814 nodes.push_back(faceNodes[inode]);
10816 // add new face based on volume nodes
10817 if (aMesh->FindFace( nodes ) ) {
10819 continue; // face already exsist
10821 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10825 return ( nbFree==(nbExisted+nbCreated) );
10830 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10832 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10834 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10837 //================================================================================
10839 * \brief Creates missing boundary elements
10840 * \param elements - elements whose boundary is to be checked
10841 * \param dimension - defines type of boundary elements to create
10842 * \param group - a group to store created boundary elements in
10843 * \param targetMesh - a mesh to store created boundary elements in
10844 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10845 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10846 * boundary elements will be copied into the targetMesh
10848 //================================================================================
10850 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10851 Bnd_Dimension dimension,
10852 SMESH_Group* group/*=0*/,
10853 SMESH_Mesh* targetMesh/*=0*/,
10854 bool toCopyElements/*=false*/,
10855 bool toCopyExistingBondary/*=false*/)
10857 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10858 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10859 // hope that all elements are of the same type, do not check them all
10860 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10861 throw SALOME_Exception(LOCALIZED("wrong element type"));
10864 toCopyElements = toCopyExistingBondary = false;
10866 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10867 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10869 SMDS_VolumeTool vTool;
10870 TIDSortedElemSet emptySet, avoidSet;
10873 typedef vector<const SMDS_MeshNode*> TConnectivity;
10875 SMDS_ElemIteratorPtr eIt;
10876 if (elements.empty())
10877 eIt = aMesh->elementsIterator(elemType);
10879 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10881 while (eIt->more())
10883 const SMDS_MeshElement* elem = eIt->next();
10884 const int iQuad = elem->IsQuadratic();
10886 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10887 vector<const SMDS_MeshElement*> presentBndElems;
10888 vector<TConnectivity> missingBndElems;
10889 TConnectivity nodes;
10890 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10892 vTool.SetExternalNormal();
10893 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10895 if (!vTool.IsFreeFace(iface))
10897 int nbFaceNodes = vTool.NbFaceNodes(iface);
10898 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10899 if ( missType == SMDSAbs_Edge ) // boundary edges
10901 nodes.resize( 2+iQuad );
10902 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10904 for ( int j = 0; j < nodes.size(); ++j )
10906 if ( const SMDS_MeshElement* edge =
10907 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10908 presentBndElems.push_back( edge );
10910 missingBndElems.push_back( nodes );
10913 else // boundary face
10916 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10917 nodes.push_back( nn[inode] );
10919 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10920 nodes.push_back( nn[inode] );
10922 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10923 presentBndElems.push_back( f );
10925 missingBndElems.push_back( nodes );
10929 else // elem is a face ------------------------------------------
10931 avoidSet.clear(), avoidSet.insert( elem );
10932 int nbNodes = elem->NbCornerNodes();
10933 nodes.resize( 2 /*+ iQuad*/);
10934 for ( int i = 0; i < nbNodes; i++ )
10936 nodes[0] = elem->GetNode(i);
10937 nodes[1] = elem->GetNode((i+1)%nbNodes);
10938 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10939 continue; // not free link
10942 //nodes[2] = elem->GetNode( i + nbNodes );
10943 if ( const SMDS_MeshElement* edge =
10944 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10945 presentBndElems.push_back( edge );
10947 missingBndElems.push_back( nodes );
10951 // 2. Add missing boundary elements
10952 if ( targetMesh != myMesh )
10953 // instead of making a map of nodes in this mesh and targetMesh,
10954 // we create nodes with same IDs. We can renumber them later, if needed
10955 for ( int i = 0; i < missingBndElems.size(); ++i )
10957 TConnectivity& srcNodes = missingBndElems[i];
10958 TConnectivity nodes( srcNodes.size() );
10959 for ( inode = 0; inode < nodes.size(); ++inode )
10960 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10961 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10964 for ( int i = 0; i < missingBndElems.size(); ++i )
10966 TConnectivity& nodes = missingBndElems[i];
10967 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10970 // 3. Copy present boundary elements
10971 if ( toCopyExistingBondary )
10972 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10974 const SMDS_MeshElement* e = presentBndElems[i];
10975 TConnectivity nodes( e->NbNodes() );
10976 for ( inode = 0; inode < nodes.size(); ++inode )
10977 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10978 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10979 // leave only missing elements in tgtEditor.myLastCreatedElems
10980 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10982 } // loop on given elements
10984 // 4. Fill group with missing boundary elements
10987 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10988 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10989 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10991 tgtEditor.myLastCreatedElems.Clear();
10993 // 5. Copy given elements
10994 if ( toCopyElements )
10996 if (elements.empty())
10997 eIt = aMesh->elementsIterator(elemType);
10999 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11000 while (eIt->more())
11002 const SMDS_MeshElement* elem = eIt->next();
11003 TConnectivity nodes( elem->NbNodes() );
11004 for ( inode = 0; inode < nodes.size(); ++inode )
11005 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11006 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11008 tgtEditor.myLastCreatedElems.Clear();