1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
29 #include "SMESH_MeshEditor.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
53 #include "utilities.h"
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101 using namespace SMESH::Controls;
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
108 //=======================================================================
109 //function : SMESH_MeshEditor
111 //=======================================================================
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114 :myMesh( theMesh ) // theMesh may be NULL
118 //=======================================================================
122 //=======================================================================
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126 const SMDSAbs_ElementType type,
130 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131 SMDS_MeshElement* e = 0;
132 int nbnode = node.size();
133 SMESHDS_Mesh* mesh = GetMeshDS();
138 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
139 else e = mesh->AddFace (node[0], node[1], node[2] );
141 else if (nbnode == 4) {
142 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
143 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
145 else if (nbnode == 6) {
146 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
147 node[4], node[5], ID);
148 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
151 else if (nbnode == 8) {
152 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
153 node[4], node[5], node[6], node[7], ID);
154 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
155 node[4], node[5], node[6], node[7] );
158 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
159 else e = mesh->AddPolygonalFace (node );
166 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
169 else if (nbnode == 5) {
170 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
172 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
175 else if (nbnode == 6) {
176 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
177 node[4], node[5], ID);
178 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
181 else if (nbnode == 8) {
182 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183 node[4], node[5], node[6], node[7], ID);
184 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
185 node[4], node[5], node[6], node[7] );
187 else if (nbnode == 10) {
188 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7],
190 node[8], node[9], ID);
191 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
192 node[4], node[5], node[6], node[7],
195 else if (nbnode == 13) {
196 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197 node[4], node[5], node[6], node[7],
198 node[8], node[9], node[10],node[11],
200 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
201 node[4], node[5], node[6], node[7],
202 node[8], node[9], node[10],node[11],
205 else if (nbnode == 15) {
206 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207 node[4], node[5], node[6], node[7],
208 node[8], node[9], node[10],node[11],
209 node[12],node[13],node[14],ID);
210 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
211 node[4], node[5], node[6], node[7],
212 node[8], node[9], node[10],node[11],
213 node[12],node[13],node[14] );
215 else if (nbnode == 20) {
216 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
217 node[4], node[5], node[6], node[7],
218 node[8], node[9], node[10],node[11],
219 node[12],node[13],node[14],node[15],
220 node[16],node[17],node[18],node[19],ID);
221 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
222 node[4], node[5], node[6], node[7],
223 node[8], node[9], node[10],node[11],
224 node[12],node[13],node[14],node[15],
225 node[16],node[17],node[18],node[19] );
232 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
233 else e = mesh->AddEdge (node[0], node[1] );
235 else if ( nbnode == 3 ) {
236 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
237 else e = mesh->AddEdge (node[0], node[1], node[2] );
241 case SMDSAbs_0DElement:
243 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
244 else e = mesh->Add0DElement (node[0] );
249 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
250 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
255 if ( e ) myLastCreatedElems.Append( e );
259 //=======================================================================
263 //=======================================================================
265 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
266 const SMDSAbs_ElementType type,
270 vector<const SMDS_MeshNode*> nodes;
271 nodes.reserve( nodeIDs.size() );
272 vector<int>::const_iterator id = nodeIDs.begin();
273 while ( id != nodeIDs.end() ) {
274 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
275 nodes.push_back( node );
279 return AddElement( nodes, type, isPoly, ID );
282 //=======================================================================
284 //purpose : Remove a node or an element.
285 // Modify a compute state of sub-meshes which become empty
286 //=======================================================================
288 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
291 myLastCreatedElems.Clear();
292 myLastCreatedNodes.Clear();
294 SMESHDS_Mesh* aMesh = GetMeshDS();
295 set< SMESH_subMesh *> smmap;
298 list<int>::const_iterator it = theIDs.begin();
299 for ( ; it != theIDs.end(); it++ ) {
300 const SMDS_MeshElement * elem;
302 elem = aMesh->FindNode( *it );
304 elem = aMesh->FindElement( *it );
308 // Notify VERTEX sub-meshes about modification
310 const SMDS_MeshNode* node = cast2Node( elem );
311 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
312 if ( int aShapeID = node->getshapeId() )
313 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
316 // Find sub-meshes to notify about modification
317 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
318 // while ( nodeIt->more() ) {
319 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
320 // const SMDS_PositionPtr& aPosition = node->GetPosition();
321 // if ( aPosition.get() ) {
322 // if ( int aShapeID = aPosition->GetShapeId() ) {
323 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
324 // smmap.insert( sm );
331 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
333 aMesh->RemoveElement( elem );
337 // Notify sub-meshes about modification
338 if ( !smmap.empty() ) {
339 set< SMESH_subMesh *>::iterator smIt;
340 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
341 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
344 // // Check if the whole mesh becomes empty
345 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
346 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
351 //=======================================================================
352 //function : FindShape
353 //purpose : Return an index of the shape theElem is on
354 // or zero if a shape not found
355 //=======================================================================
357 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
359 myLastCreatedElems.Clear();
360 myLastCreatedNodes.Clear();
362 SMESHDS_Mesh * aMesh = GetMeshDS();
363 if ( aMesh->ShapeToMesh().IsNull() )
366 if ( theElem->GetType() == SMDSAbs_Node )
368 int aShapeID = theElem->getshapeId();
375 TopoDS_Shape aShape; // the shape a node is on
376 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
377 while ( nodeIt->more() ) {
378 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
379 int aShapeID = node->getshapeId();
381 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
383 if ( sm->Contains( theElem ))
385 if ( aShape.IsNull() )
386 aShape = aMesh->IndexToShape( aShapeID );
389 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
394 // None of nodes is on a proper shape,
395 // find the shape among ancestors of aShape on which a node is
396 if ( aShape.IsNull() ) {
397 //MESSAGE ("::FindShape() - NONE node is on shape")
400 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
401 for ( ; ancIt.More(); ancIt.Next() ) {
402 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
403 if ( sm && sm->Contains( theElem ))
404 return aMesh->ShapeToIndex( ancIt.Value() );
407 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
411 //=======================================================================
412 //function : IsMedium
414 //=======================================================================
416 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
417 const SMDSAbs_ElementType typeToCheck)
419 bool isMedium = false;
420 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
421 while (it->more() && !isMedium ) {
422 const SMDS_MeshElement* elem = it->next();
423 isMedium = elem->IsMediumNode(node);
428 //=======================================================================
429 //function : ShiftNodesQuadTria
431 // Shift nodes in the array corresponded to quadratic triangle
432 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
433 //=======================================================================
434 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
436 const SMDS_MeshNode* nd1 = aNodes[0];
437 aNodes[0] = aNodes[1];
438 aNodes[1] = aNodes[2];
440 const SMDS_MeshNode* nd2 = aNodes[3];
441 aNodes[3] = aNodes[4];
442 aNodes[4] = aNodes[5];
446 //=======================================================================
447 //function : GetNodesFromTwoTria
449 // Shift nodes in the array corresponded to quadratic triangle
450 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
451 //=======================================================================
452 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
453 const SMDS_MeshElement * theTria2,
454 const SMDS_MeshNode* N1[],
455 const SMDS_MeshNode* N2[])
457 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
460 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
463 if(it->more()) return false;
464 it = theTria2->nodesIterator();
467 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
470 if(it->more()) return false;
472 int sames[3] = {-1,-1,-1};
484 if(nbsames!=2) return false;
486 ShiftNodesQuadTria(N1);
488 ShiftNodesQuadTria(N1);
491 i = sames[0] + sames[1] + sames[2];
493 ShiftNodesQuadTria(N2);
495 // now we receive following N1 and N2 (using numeration as above image)
496 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
497 // i.e. first nodes from both arrays determ new diagonal
501 //=======================================================================
502 //function : InverseDiag
503 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
504 // but having other common link.
505 // Return False if args are improper
506 //=======================================================================
508 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
509 const SMDS_MeshElement * theTria2 )
511 MESSAGE("InverseDiag");
512 myLastCreatedElems.Clear();
513 myLastCreatedNodes.Clear();
515 if (!theTria1 || !theTria2)
518 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
519 if (!F1) return false;
520 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
521 if (!F2) return false;
522 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
523 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
525 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
526 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
530 // put nodes in array and find out indices of the same ones
531 const SMDS_MeshNode* aNodes [6];
532 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
534 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
535 while ( it->more() ) {
536 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
538 if ( i > 2 ) // theTria2
539 // find same node of theTria1
540 for ( int j = 0; j < 3; j++ )
541 if ( aNodes[ i ] == aNodes[ j ]) {
550 return false; // theTria1 is not a triangle
551 it = theTria2->nodesIterator();
553 if ( i == 6 && it->more() )
554 return false; // theTria2 is not a triangle
557 // find indices of 1,2 and of A,B in theTria1
558 int iA = 0, iB = 0, i1 = 0, i2 = 0;
559 for ( i = 0; i < 6; i++ ) {
560 if ( sameInd [ i ] == 0 ) {
569 // nodes 1 and 2 should not be the same
570 if ( aNodes[ i1 ] == aNodes[ i2 ] )
574 aNodes[ iA ] = aNodes[ i2 ];
576 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
578 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
579 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
583 } // end if(F1 && F2)
585 // check case of quadratic faces
586 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
588 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
592 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
593 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
601 const SMDS_MeshNode* N1 [6];
602 const SMDS_MeshNode* N2 [6];
603 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
605 // now we receive following N1 and N2 (using numeration as above image)
606 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
607 // i.e. first nodes from both arrays determ new diagonal
609 const SMDS_MeshNode* N1new [6];
610 const SMDS_MeshNode* N2new [6];
623 // replaces nodes in faces
624 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
625 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
630 //=======================================================================
631 //function : findTriangles
632 //purpose : find triangles sharing theNode1-theNode2 link
633 //=======================================================================
635 static bool findTriangles(const SMDS_MeshNode * theNode1,
636 const SMDS_MeshNode * theNode2,
637 const SMDS_MeshElement*& theTria1,
638 const SMDS_MeshElement*& theTria2)
640 if ( !theNode1 || !theNode2 ) return false;
642 theTria1 = theTria2 = 0;
644 set< const SMDS_MeshElement* > emap;
645 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
647 const SMDS_MeshElement* elem = it->next();
648 if ( elem->NbNodes() == 3 )
651 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
653 const SMDS_MeshElement* elem = it->next();
654 if ( emap.find( elem ) != emap.end() ) {
656 // theTria1 must be element with minimum ID
657 if( theTria1->GetID() < elem->GetID() ) {
671 return ( theTria1 && theTria2 );
674 //=======================================================================
675 //function : InverseDiag
676 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
677 // with ones built on the same 4 nodes but having other common link.
678 // Return false if proper faces not found
679 //=======================================================================
681 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
682 const SMDS_MeshNode * theNode2)
684 myLastCreatedElems.Clear();
685 myLastCreatedNodes.Clear();
687 MESSAGE( "::InverseDiag()" );
689 const SMDS_MeshElement *tr1, *tr2;
690 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
693 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
694 if (!F1) return false;
695 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
696 if (!F2) return false;
697 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
698 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
700 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
701 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
705 // put nodes in array
706 // and find indices of 1,2 and of A in tr1 and of B in tr2
707 int i, iA1 = 0, i1 = 0;
708 const SMDS_MeshNode* aNodes1 [3];
709 SMDS_ElemIteratorPtr it;
710 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
711 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
712 if ( aNodes1[ i ] == theNode1 )
713 iA1 = i; // node A in tr1
714 else if ( aNodes1[ i ] != theNode2 )
718 const SMDS_MeshNode* aNodes2 [3];
719 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
720 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
721 if ( aNodes2[ i ] == theNode2 )
722 iB2 = i; // node B in tr2
723 else if ( aNodes2[ i ] != theNode1 )
727 // nodes 1 and 2 should not be the same
728 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
732 aNodes1[ iA1 ] = aNodes2[ i2 ];
734 aNodes2[ iB2 ] = aNodes1[ i1 ];
736 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
737 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
742 // check case of quadratic faces
743 return InverseDiag(tr1,tr2);
746 //=======================================================================
747 //function : getQuadrangleNodes
748 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
749 // fusion of triangles tr1 and tr2 having shared link on
750 // theNode1 and theNode2
751 //=======================================================================
753 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
754 const SMDS_MeshNode * theNode1,
755 const SMDS_MeshNode * theNode2,
756 const SMDS_MeshElement * tr1,
757 const SMDS_MeshElement * tr2 )
759 if( tr1->NbNodes() != tr2->NbNodes() )
761 // find the 4-th node to insert into tr1
762 const SMDS_MeshNode* n4 = 0;
763 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
765 while ( !n4 && i<3 ) {
766 const SMDS_MeshNode * n = cast2Node( it->next() );
768 bool isDiag = ( n == theNode1 || n == theNode2 );
772 // Make an array of nodes to be in a quadrangle
773 int iNode = 0, iFirstDiag = -1;
774 it = tr1->nodesIterator();
777 const SMDS_MeshNode * n = cast2Node( it->next() );
779 bool isDiag = ( n == theNode1 || n == theNode2 );
781 if ( iFirstDiag < 0 )
783 else if ( iNode - iFirstDiag == 1 )
784 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
786 else if ( n == n4 ) {
787 return false; // tr1 and tr2 should not have all the same nodes
789 theQuadNodes[ iNode++ ] = n;
791 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
792 theQuadNodes[ iNode ] = n4;
797 //=======================================================================
798 //function : DeleteDiag
799 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
800 // with a quadrangle built on the same 4 nodes.
801 // Return false if proper faces not found
802 //=======================================================================
804 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
805 const SMDS_MeshNode * theNode2)
807 myLastCreatedElems.Clear();
808 myLastCreatedNodes.Clear();
810 MESSAGE( "::DeleteDiag()" );
812 const SMDS_MeshElement *tr1, *tr2;
813 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
816 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
817 if (!F1) return false;
818 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
819 if (!F2) return false;
820 SMESHDS_Mesh * aMesh = GetMeshDS();
822 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
823 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
825 const SMDS_MeshNode* aNodes [ 4 ];
826 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
829 const SMDS_MeshElement* newElem = 0;
830 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
831 myLastCreatedElems.Append(newElem);
832 AddToSameGroups( newElem, tr1, aMesh );
833 int aShapeId = tr1->getshapeId();
836 aMesh->SetMeshElementOnShape( newElem, aShapeId );
838 aMesh->RemoveElement( tr1 );
839 aMesh->RemoveElement( tr2 );
844 // check case of quadratic faces
845 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
847 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
851 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
852 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
860 const SMDS_MeshNode* N1 [6];
861 const SMDS_MeshNode* N2 [6];
862 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
864 // now we receive following N1 and N2 (using numeration as above image)
865 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
866 // i.e. first nodes from both arrays determ new diagonal
868 const SMDS_MeshNode* aNodes[8];
878 const SMDS_MeshElement* newElem = 0;
879 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
880 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
881 myLastCreatedElems.Append(newElem);
882 AddToSameGroups( newElem, tr1, aMesh );
883 int aShapeId = tr1->getshapeId();
886 aMesh->SetMeshElementOnShape( newElem, aShapeId );
888 aMesh->RemoveElement( tr1 );
889 aMesh->RemoveElement( tr2 );
891 // remove middle node (9)
892 GetMeshDS()->RemoveNode( N1[4] );
897 //=======================================================================
898 //function : Reorient
899 //purpose : Reverse theElement orientation
900 //=======================================================================
902 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
905 myLastCreatedElems.Clear();
906 myLastCreatedNodes.Clear();
910 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
911 if ( !it || !it->more() )
914 switch ( theElem->GetType() ) {
918 if(!theElem->IsQuadratic()) {
919 int i = theElem->NbNodes();
920 vector<const SMDS_MeshNode*> aNodes( i );
922 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
923 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
926 // quadratic elements
927 if(theElem->GetType()==SMDSAbs_Edge) {
928 vector<const SMDS_MeshNode*> aNodes(3);
929 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
930 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
931 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
932 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
935 int nbn = theElem->NbNodes();
936 vector<const SMDS_MeshNode*> aNodes(nbn);
937 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
939 for(; i<nbn/2; i++) {
940 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
942 for(i=0; i<nbn/2; i++) {
943 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
945 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
949 case SMDSAbs_Volume: {
950 if (theElem->IsPoly()) {
951 // TODO reorient vtk polyhedron
952 MESSAGE("reorient vtk polyhedron ?");
953 const SMDS_VtkVolume* aPolyedre =
954 dynamic_cast<const SMDS_VtkVolume*>( theElem );
956 MESSAGE("Warning: bad volumic element");
960 int nbFaces = aPolyedre->NbFaces();
961 vector<const SMDS_MeshNode *> poly_nodes;
962 vector<int> quantities (nbFaces);
964 // reverse each face of the polyedre
965 for (int iface = 1; iface <= nbFaces; iface++) {
966 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
967 quantities[iface - 1] = nbFaceNodes;
969 for (inode = nbFaceNodes; inode >= 1; inode--) {
970 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
971 poly_nodes.push_back(curNode);
975 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
979 SMDS_VolumeTool vTool;
980 if ( !vTool.Set( theElem ))
983 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
984 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
993 //=======================================================================
994 //function : getBadRate
996 //=======================================================================
998 static double getBadRate (const SMDS_MeshElement* theElem,
999 SMESH::Controls::NumericalFunctorPtr& theCrit)
1001 SMESH::Controls::TSequenceOfXYZ P;
1002 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1004 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1005 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1008 //=======================================================================
1009 //function : QuadToTri
1010 //purpose : Cut quadrangles into triangles.
1011 // theCrit is used to select a diagonal to cut
1012 //=======================================================================
1014 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1015 SMESH::Controls::NumericalFunctorPtr theCrit)
1017 myLastCreatedElems.Clear();
1018 myLastCreatedNodes.Clear();
1020 MESSAGE( "::QuadToTri()" );
1022 if ( !theCrit.get() )
1025 SMESHDS_Mesh * aMesh = GetMeshDS();
1027 Handle(Geom_Surface) surface;
1028 SMESH_MesherHelper helper( *GetMesh() );
1030 TIDSortedElemSet::iterator itElem;
1031 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1032 const SMDS_MeshElement* elem = *itElem;
1033 if ( !elem || elem->GetType() != SMDSAbs_Face )
1035 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1038 // retrieve element nodes
1039 const SMDS_MeshNode* aNodes [8];
1040 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1042 while ( itN->more() )
1043 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1045 // compare two sets of possible triangles
1046 double aBadRate1, aBadRate2; // to what extent a set is bad
1047 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1048 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1049 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1051 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1052 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1053 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1055 int aShapeId = FindShape( elem );
1056 const SMDS_MeshElement* newElem1 = 0;
1057 const SMDS_MeshElement* newElem2 = 0;
1059 if( !elem->IsQuadratic() ) {
1061 // split liner quadrangle
1062 if ( aBadRate1 <= aBadRate2 ) {
1063 // tr1 + tr2 is better
1064 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1065 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1068 // tr3 + tr4 is better
1069 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1070 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1075 // split quadratic quadrangle
1077 // get surface elem is on
1078 if ( aShapeId != helper.GetSubShapeID() ) {
1082 shape = aMesh->IndexToShape( aShapeId );
1083 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1084 TopoDS_Face face = TopoDS::Face( shape );
1085 surface = BRep_Tool::Surface( face );
1086 if ( !surface.IsNull() )
1087 helper.SetSubShape( shape );
1091 const SMDS_MeshNode* aNodes [8];
1092 const SMDS_MeshNode* inFaceNode = 0;
1093 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1095 while ( itN->more() ) {
1096 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1097 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1098 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1100 inFaceNode = aNodes[ i-1 ];
1103 // find middle point for (0,1,2,3)
1104 // and create a node in this point;
1106 if ( surface.IsNull() ) {
1108 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1112 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1115 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1117 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1119 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1120 myLastCreatedNodes.Append(newN);
1122 // create a new element
1123 const SMDS_MeshNode* N[6];
1124 if ( aBadRate1 <= aBadRate2 ) {
1131 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1132 aNodes[6], aNodes[7], newN );
1133 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1134 newN, aNodes[4], aNodes[5] );
1143 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1144 aNodes[7], aNodes[4], newN );
1145 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1146 newN, aNodes[5], aNodes[6] );
1150 // care of a new element
1152 myLastCreatedElems.Append(newElem1);
1153 myLastCreatedElems.Append(newElem2);
1154 AddToSameGroups( newElem1, elem, aMesh );
1155 AddToSameGroups( newElem2, elem, aMesh );
1157 // put a new triangle on the same shape
1160 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1161 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1163 aMesh->RemoveElement( elem );
1168 //=======================================================================
1169 //function : BestSplit
1170 //purpose : Find better diagonal for cutting.
1171 //=======================================================================
1173 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1174 SMESH::Controls::NumericalFunctorPtr theCrit)
1176 myLastCreatedElems.Clear();
1177 myLastCreatedNodes.Clear();
1182 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1185 if( theQuad->NbNodes()==4 ||
1186 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1188 // retrieve element nodes
1189 const SMDS_MeshNode* aNodes [4];
1190 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1192 //while (itN->more())
1194 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1196 // compare two sets of possible triangles
1197 double aBadRate1, aBadRate2; // to what extent a set is bad
1198 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1199 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1200 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1202 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1203 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1204 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1206 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1207 return 1; // diagonal 1-3
1209 return 2; // diagonal 2-4
1216 // Methods of splitting volumes into tetra
1218 const int theHexTo5_1[5*4+1] =
1220 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1222 const int theHexTo5_2[5*4+1] =
1224 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1226 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1228 const int theHexTo6_1[6*4+1] =
1230 1, 5, 6, 0, 0, 1, 2, 6, 0, 4, 5, 6, 0, 4, 6, 7, 0, 2, 3, 6, 0, 3, 7, 6, -1
1232 const int theHexTo6_2[6*4+1] =
1234 2, 6, 7, 1, 1, 2, 3, 7, 1, 5, 6, 7, 1, 5, 7, 4, 1, 3, 0, 7, 1, 0, 4, 7, -1
1236 const int theHexTo6_3[6*4+1] =
1238 3, 7, 4, 2, 2, 3, 0, 4, 2, 6, 7, 4, 2, 6, 4, 5, 2, 0, 1, 4, 2, 1, 5, 4, -1
1240 const int theHexTo6_4[6*4+1] =
1242 0, 4, 5, 3, 3, 0, 1, 5, 3, 7, 4, 5, 3, 7, 5, 6, 3, 1, 2, 5, 3, 2, 6, 5, -1
1244 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1246 const int thePyraTo2_1[2*4+1] =
1248 0, 1, 2, 4, 0, 2, 3, 4, -1
1250 const int thePyraTo2_2[2*4+1] =
1252 1, 2, 3, 4, 1, 3, 0, 4, -1
1254 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1256 const int thePentaTo3_1[3*4+1] =
1258 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1260 const int thePentaTo3_2[3*4+1] =
1262 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1264 const int thePentaTo3_3[3*4+1] =
1266 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1268 const int thePentaTo3_4[3*4+1] =
1270 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1272 const int thePentaTo3_5[3*4+1] =
1274 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1276 const int thePentaTo3_6[3*4+1] =
1278 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1280 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1281 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1283 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1286 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1287 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1288 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1293 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1294 bool _baryNode; //!< additional node is to be created at cell barycenter
1295 bool _ownConn; //!< to delete _connectivity in destructor
1296 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1298 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1299 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1300 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1301 bool hasFacet( const TTriangleFacet& facet ) const
1303 const int* tetConn = _connectivity;
1304 for ( ; tetConn[0] >= 0; tetConn += 4 )
1305 if (( facet.contains( tetConn[0] ) +
1306 facet.contains( tetConn[1] ) +
1307 facet.contains( tetConn[2] ) +
1308 facet.contains( tetConn[3] )) == 3 )
1314 //=======================================================================
1316 * \brief return TSplitMethod for the given element
1318 //=======================================================================
1320 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1322 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1324 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1325 // an edge and a face barycenter; tertaherdons are based on triangles and
1326 // a volume barycenter
1327 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1329 // Find out how adjacent volumes are split
1331 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1332 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1333 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1335 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1336 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1337 if ( nbNodes < 4 ) continue;
1339 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1340 const int* nInd = vol.GetFaceNodesIndices( iF );
1343 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1344 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1345 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1346 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1350 int iCom = 0; // common node of triangle faces to split into
1351 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1353 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1354 nInd[ iQ * ( (iCom+1)%nbNodes )],
1355 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1356 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1357 nInd[ iQ * ( (iCom+2)%nbNodes )],
1358 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1359 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1361 triaSplits.push_back( t012 );
1362 triaSplits.push_back( t023 );
1367 if ( !triaSplits.empty() )
1368 hasAdjacentSplits = true;
1371 // Among variants of split method select one compliant with adjacent volumes
1373 TSplitMethod method;
1374 if ( !vol.Element()->IsPoly() && !is24TetMode )
1376 int nbVariants = 2, nbTet = 0;
1377 const int** connVariants = 0;
1378 switch ( vol.Element()->GetEntityType() )
1380 case SMDSEntity_Hexa:
1381 case SMDSEntity_Quad_Hexa:
1382 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1383 connVariants = theHexTo5, nbTet = 5;
1385 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1387 case SMDSEntity_Pyramid:
1388 case SMDSEntity_Quad_Pyramid:
1389 connVariants = thePyraTo2; nbTet = 2;
1391 case SMDSEntity_Penta:
1392 case SMDSEntity_Quad_Penta:
1393 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1398 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1400 // check method compliancy with adjacent tetras,
1401 // all found splits must be among facets of tetras described by this method
1402 method = TSplitMethod( nbTet, connVariants[variant] );
1403 if ( hasAdjacentSplits && method._nbTetra > 0 )
1405 bool facetCreated = true;
1406 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1408 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1409 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1410 facetCreated = method.hasFacet( *facet );
1412 if ( !facetCreated )
1413 method = TSplitMethod(0); // incompatible method
1417 if ( method._nbTetra < 1 )
1419 // No standard method is applicable, use a generic solution:
1420 // each facet of a volume is split into triangles and
1421 // each of triangles and a volume barycenter form a tetrahedron.
1423 int* connectivity = new int[ maxTetConnSize + 1 ];
1424 method._connectivity = connectivity;
1425 method._ownConn = true;
1426 method._baryNode = true;
1429 int baryCenInd = vol.NbNodes();
1430 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1432 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1433 const int* nInd = vol.GetFaceNodesIndices( iF );
1434 // find common node of triangle facets of tetra to create
1435 int iCommon = 0; // index in linear numeration
1436 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1437 if ( !triaSplits.empty() )
1440 const TTriangleFacet* facet = &triaSplits.front();
1441 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1442 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1443 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1446 else if ( nbNodes > 3 && !is24TetMode )
1448 // find the best method of splitting into triangles by aspect ratio
1449 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1450 map< double, int > badness2iCommon;
1451 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1452 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1453 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1454 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1456 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1457 nodes[ iQ*((iLast-1)%nbNodes)],
1458 nodes[ iQ*((iLast )%nbNodes)]);
1459 double badness = getBadRate( &tria, aspectRatio );
1460 badness2iCommon.insert( make_pair( badness, iCommon ));
1462 // use iCommon with lowest badness
1463 iCommon = badness2iCommon.begin()->second;
1465 if ( iCommon >= nbNodes )
1466 iCommon = 0; // something wrong
1468 // fill connectivity of tetrahedra based on a current face
1469 int nbTet = nbNodes - 2;
1470 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1472 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1473 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1475 for ( int i = 0; i < nbTet; ++i )
1477 int i1 = i, i2 = (i+1) % nbNodes;
1478 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1479 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1480 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1481 connectivity[ connSize++ ] = faceBaryCenInd;
1482 connectivity[ connSize++ ] = baryCenInd;
1487 for ( int i = 0; i < nbTet; ++i )
1489 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1490 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1492 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1493 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1494 connectivity[ connSize++ ] = baryCenInd;
1497 method._nbTetra += nbTet;
1499 connectivity[ connSize++ ] = -1;
1503 //================================================================================
1505 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1507 //================================================================================
1509 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1511 // find the tetrahedron including the three nodes of facet
1512 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1513 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1514 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1515 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1516 while ( volIt1->more() )
1518 const SMDS_MeshElement* v = volIt1->next();
1519 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1521 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1522 while ( volIt2->more() )
1523 if ( v != volIt2->next() )
1525 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1526 while ( volIt3->more() )
1527 if ( v == volIt3->next() )
1533 //=======================================================================
1535 * \brief A key of a face of volume
1537 //=======================================================================
1539 struct TVolumeFaceKey: pair< int, pair< int, int> >
1541 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1543 TIDSortedNodeSet sortedNodes;
1544 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1545 int nbNodes = vol.NbFaceNodes( iF );
1546 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1547 for ( int i = 0; i < nbNodes; i += iQ )
1548 sortedNodes.insert( fNodes[i] );
1549 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1550 first = (*(n++))->GetID();
1551 second.first = (*(n++))->GetID();
1552 second.second = (*(n++))->GetID();
1557 //=======================================================================
1558 //function : SplitVolumesIntoTetra
1559 //purpose : Split volumic elements into tetrahedra.
1560 //=======================================================================
1562 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1563 const int theMethodFlags)
1565 // std-like iterator on coordinates of nodes of mesh element
1566 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1567 NXyzIterator xyzEnd;
1569 SMDS_VolumeTool volTool;
1570 SMESH_MesherHelper helper( *GetMesh());
1572 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1573 SMESHDS_SubMesh* fSubMesh = 0;//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_TNodeXYZ( *nIt ) );
6245 if ( minSqDist > sqDist ) {
6253 //---------------------------------------------------------------------
6257 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6259 //---------------------------------------------------------------------
6261 * \brief Return the node tree
6263 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6266 SMESH_OctreeNode* myOctreeNode;
6267 SMESHDS_Mesh* myMesh;
6268 double myHalfLeafSize; // max size of a leaf box
6271 //=======================================================================
6273 * \brief Return SMESH_NodeSearcher
6275 //=======================================================================
6277 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6279 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6282 // ========================================================================
6283 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6285 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6286 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6287 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6289 //=======================================================================
6291 * \brief Octal tree of bounding boxes of elements
6293 //=======================================================================
6295 class ElementBndBoxTree : public SMESH_Octree
6299 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6300 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6301 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6302 ~ElementBndBoxTree();
6305 ElementBndBoxTree() {}
6306 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6307 void buildChildrenData();
6308 Bnd_B3d* buildRootBox();
6310 //!< Bounding box of element
6311 struct ElementBox : public Bnd_B3d
6313 const SMDS_MeshElement* _element;
6314 int _refCount; // an ElementBox can be included in several tree branches
6315 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6317 vector< ElementBox* > _elements;
6320 //================================================================================
6322 * \brief ElementBndBoxTree creation
6324 //================================================================================
6326 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6327 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6329 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6330 _elements.reserve( nbElems );
6332 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6333 while ( elemIt->more() )
6334 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6336 if ( _elements.size() > MaxNbElemsInLeaf )
6342 //================================================================================
6346 //================================================================================
6348 ElementBndBoxTree::~ElementBndBoxTree()
6350 for ( int i = 0; i < _elements.size(); ++i )
6351 if ( --_elements[i]->_refCount <= 0 )
6352 delete _elements[i];
6355 //================================================================================
6357 * \brief Return the maximal box
6359 //================================================================================
6361 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6363 Bnd_B3d* box = new Bnd_B3d;
6364 for ( int i = 0; i < _elements.size(); ++i )
6365 box->Add( *_elements[i] );
6369 //================================================================================
6371 * \brief Redistrubute element boxes among children
6373 //================================================================================
6375 void ElementBndBoxTree::buildChildrenData()
6377 for ( int i = 0; i < _elements.size(); ++i )
6379 for (int j = 0; j < 8; j++)
6381 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6383 _elements[i]->_refCount++;
6384 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6387 _elements[i]->_refCount--;
6391 for (int j = 0; j < 8; j++)
6393 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6394 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6395 child->myIsLeaf = true;
6397 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6398 child->_elements.resize( child->_elements.size() ); // compact
6402 //================================================================================
6404 * \brief Return elements which can include the point
6406 //================================================================================
6408 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6409 TIDSortedElemSet& foundElems)
6411 if ( level() && getBox().IsOut( point.XYZ() ))
6416 for ( int i = 0; i < _elements.size(); ++i )
6417 if ( !_elements[i]->IsOut( point.XYZ() ))
6418 foundElems.insert( _elements[i]->_element );
6422 for (int i = 0; i < 8; i++)
6423 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6427 //================================================================================
6429 * \brief Return elements which can be intersected by the line
6431 //================================================================================
6433 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6434 TIDSortedElemSet& foundElems)
6436 if ( level() && getBox().IsOut( line ))
6441 for ( int i = 0; i < _elements.size(); ++i )
6442 if ( !_elements[i]->IsOut( line ))
6443 foundElems.insert( _elements[i]->_element );
6447 for (int i = 0; i < 8; i++)
6448 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6452 //================================================================================
6454 * \brief Construct the element box
6456 //================================================================================
6458 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6462 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6463 while ( nIt->more() )
6464 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6465 Enlarge( tolerance );
6470 //=======================================================================
6472 * \brief Implementation of search for the elements by point and
6473 * of classification of point in 2D mesh
6475 //=======================================================================
6477 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6479 SMESHDS_Mesh* _mesh;
6480 SMDS_ElemIteratorPtr _meshPartIt;
6481 ElementBndBoxTree* _ebbTree;
6482 SMESH_NodeSearcherImpl* _nodeSearcher;
6483 SMDSAbs_ElementType _elementType;
6485 bool _outerFacesFound;
6486 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6488 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6489 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6490 ~SMESH_ElementSearcherImpl()
6492 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6493 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6495 virtual int FindElementsByPoint(const gp_Pnt& point,
6496 SMDSAbs_ElementType type,
6497 vector< const SMDS_MeshElement* >& foundElements);
6498 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6500 void GetElementsNearLine( const gp_Ax1& line,
6501 SMDSAbs_ElementType type,
6502 vector< const SMDS_MeshElement* >& foundElems);
6503 double getTolerance();
6504 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6505 const double tolerance, double & param);
6506 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6507 bool isOuterBoundary(const SMDS_MeshElement* face) const
6509 return _outerFaces.empty() || _outerFaces.count(face);
6511 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6513 const SMDS_MeshElement* _face;
6515 bool _coincides; //!< the line lays in face plane
6516 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6517 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6519 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6522 TIDSortedElemSet _faces;
6523 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6524 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6528 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6530 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6531 << ", _coincides="<<i._coincides << ")";
6534 //=======================================================================
6536 * \brief define tolerance for search
6538 //=======================================================================
6540 double SMESH_ElementSearcherImpl::getTolerance()
6542 if ( _tolerance < 0 )
6544 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6547 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6549 double boxSize = _nodeSearcher->getTree()->maxSize();
6550 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6552 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6554 double boxSize = _ebbTree->maxSize();
6555 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6557 if ( _tolerance == 0 )
6559 // define tolerance by size of a most complex element
6560 int complexType = SMDSAbs_Volume;
6561 while ( complexType > SMDSAbs_All &&
6562 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6564 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6566 if ( complexType == int( SMDSAbs_Node ))
6568 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6570 if ( meshInfo.NbNodes() > 2 )
6571 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6575 SMDS_ElemIteratorPtr elemIt =
6576 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6577 const SMDS_MeshElement* elem = elemIt->next();
6578 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6579 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6581 while ( nodeIt->more() )
6583 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6584 elemSize = max( dist, elemSize );
6587 _tolerance = 1e-4 * elemSize;
6593 //================================================================================
6595 * \brief Find intersection of the line and an edge of face and return parameter on line
6597 //================================================================================
6599 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6600 const SMDS_MeshElement* face,
6607 GeomAPI_ExtremaCurveCurve anExtCC;
6608 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6610 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6611 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6613 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6614 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6615 anExtCC.Init( lineCurve, edge);
6616 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6618 Quantity_Parameter pl, pe;
6619 anExtCC.LowerDistanceParameters( pl, pe );
6621 if ( ++nbInts == 2 )
6625 if ( nbInts > 0 ) param /= nbInts;
6628 //================================================================================
6630 * \brief Find all faces belonging to the outer boundary of mesh
6632 //================================================================================
6634 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6636 if ( _outerFacesFound ) return;
6638 // Collect all outer faces by passing from one outer face to another via their links
6639 // and BTW find out if there are internal faces at all.
6641 // checked links and links where outer boundary meets internal one
6642 set< SMESH_TLink > visitedLinks, seamLinks;
6644 // links to treat with already visited faces sharing them
6645 list < TFaceLink > startLinks;
6647 // load startLinks with the first outerFace
6648 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6649 _outerFaces.insert( outerFace );
6651 TIDSortedElemSet emptySet;
6652 while ( !startLinks.empty() )
6654 const SMESH_TLink& link = startLinks.front()._link;
6655 TIDSortedElemSet& faces = startLinks.front()._faces;
6657 outerFace = *faces.begin();
6658 // find other faces sharing the link
6659 const SMDS_MeshElement* f;
6660 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6663 // select another outer face among the found
6664 const SMDS_MeshElement* outerFace2 = 0;
6665 if ( faces.size() == 2 )
6667 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6669 else if ( faces.size() > 2 )
6671 seamLinks.insert( link );
6673 // link direction within the outerFace
6674 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6675 SMESH_TNodeXYZ( link.node2()));
6676 int i1 = outerFace->GetNodeIndex( link.node1() );
6677 int i2 = outerFace->GetNodeIndex( link.node2() );
6678 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6679 if ( rev ) n1n2.Reverse();
6681 gp_XYZ ofNorm, fNorm;
6682 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6684 // direction from the link inside outerFace
6685 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6686 // sort all other faces by angle with the dirInOF
6687 map< double, const SMDS_MeshElement* > angle2Face;
6688 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6689 for ( ; face != faces.end(); ++face )
6691 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6693 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6694 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6695 if ( angle < 0 ) angle += 2*PI;
6696 angle2Face.insert( make_pair( angle, *face ));
6698 if ( !angle2Face.empty() )
6699 outerFace2 = angle2Face.begin()->second;
6702 // store the found outer face and add its links to continue seaching from
6705 _outerFaces.insert( outerFace );
6706 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6707 for ( int i = 0; i < nbNodes; ++i )
6709 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6710 if ( visitedLinks.insert( link2 ).second )
6711 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6714 startLinks.pop_front();
6716 _outerFacesFound = true;
6718 if ( !seamLinks.empty() )
6720 // There are internal boundaries touching the outher one,
6721 // find all faces of internal boundaries in order to find
6722 // faces of boundaries of holes, if any.
6727 _outerFaces.clear();
6731 //=======================================================================
6733 * \brief Find elements of given type where the given point is IN or ON.
6734 * Returns nb of found elements and elements them-selves.
6736 * 'ALL' type means elements of any type excluding nodes and 0D elements
6738 //=======================================================================
6740 int SMESH_ElementSearcherImpl::
6741 FindElementsByPoint(const gp_Pnt& point,
6742 SMDSAbs_ElementType type,
6743 vector< const SMDS_MeshElement* >& foundElements)
6745 foundElements.clear();
6747 double tolerance = getTolerance();
6749 // =================================================================================
6750 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6752 if ( !_nodeSearcher )
6753 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6755 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6756 if ( !closeNode ) return foundElements.size();
6758 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6759 return foundElements.size(); // to far from any node
6761 if ( type == SMDSAbs_Node )
6763 foundElements.push_back( closeNode );
6767 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6768 while ( elemIt->more() )
6769 foundElements.push_back( elemIt->next() );
6772 // =================================================================================
6773 else // elements more complex than 0D
6775 if ( !_ebbTree || _elementType != type )
6777 if ( _ebbTree ) delete _ebbTree;
6778 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6780 TIDSortedElemSet suspectElems;
6781 _ebbTree->getElementsNearPoint( point, suspectElems );
6782 TIDSortedElemSet::iterator elem = suspectElems.begin();
6783 for ( ; elem != suspectElems.end(); ++elem )
6784 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6785 foundElements.push_back( *elem );
6787 return foundElements.size();
6790 //================================================================================
6792 * \brief Classify the given point in the closed 2D mesh
6794 //================================================================================
6796 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6798 double tolerance = getTolerance();
6799 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6801 if ( _ebbTree ) delete _ebbTree;
6802 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6804 // Algo: analyse transition of a line starting at the point through mesh boundary;
6805 // try three lines parallel to axis of the coordinate system and perform rough
6806 // analysis. If solution is not clear perform thorough analysis.
6808 const int nbAxes = 3;
6809 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6810 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6811 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6812 multimap< int, int > nbInt2Axis; // to find the simplest case
6813 for ( int axis = 0; axis < nbAxes; ++axis )
6815 gp_Ax1 lineAxis( point, axisDir[axis]);
6816 gp_Lin line ( lineAxis );
6818 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6819 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6821 // Intersect faces with the line
6823 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6824 TIDSortedElemSet::iterator face = suspectFaces.begin();
6825 for ( ; face != suspectFaces.end(); ++face )
6829 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6830 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6832 // perform intersection
6833 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6834 if ( !intersection.IsDone() )
6836 if ( intersection.IsInQuadric() )
6838 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6840 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6842 gp_Pnt intersectionPoint = intersection.Point(1);
6843 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6844 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6847 // Analyse intersections roughly
6849 int nbInter = u2inters.size();
6853 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6854 if ( nbInter == 1 ) // not closed mesh
6855 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6857 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6860 if ( (f<0) == (l<0) )
6863 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6864 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6865 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6868 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6870 if ( _outerFacesFound ) break; // pass to thorough analysis
6872 } // three attempts - loop on CS axes
6874 // Analyse intersections thoroughly.
6875 // We make two loops maximum, on the first one we only exclude touching intersections,
6876 // on the second, if situation is still unclear, we gather and use information on
6877 // position of faces (internal or outer). If faces position is already gathered,
6878 // we make the second loop right away.
6880 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6882 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6883 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6885 int axis = nb_axis->second;
6886 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6888 gp_Ax1 lineAxis( point, axisDir[axis]);
6889 gp_Lin line ( lineAxis );
6891 // add tangent intersections to u2inters
6893 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6894 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6895 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6896 u2inters.insert(make_pair( param, *tgtInt ));
6897 tangentInters[ axis ].clear();
6899 // Count intersections before and after the point excluding touching ones.
6900 // If hasPositionInfo we count intersections of outer boundary only
6902 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6903 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6904 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6905 bool ok = ! u_int1->second._coincides;
6906 while ( ok && u_int1 != u2inters.end() )
6908 double u = u_int1->first;
6909 bool touchingInt = false;
6910 if ( ++u_int2 != u2inters.end() )
6912 // skip intersections at the same point (if the line passes through edge or node)
6914 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6920 // skip tangent intersections
6922 const SMDS_MeshElement* prevFace = u_int1->second._face;
6923 while ( ok && u_int2->second._coincides )
6925 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6931 ok = ( u_int2 != u2inters.end() );
6936 // skip intersections at the same point after tangent intersections
6939 double u2 = u_int2->first;
6941 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6947 // decide if we skipped a touching intersection
6948 if ( nbSamePnt + nbTgt > 0 )
6950 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6951 map< double, TInters >::iterator u_int = u_int1;
6952 for ( ; u_int != u_int2; ++u_int )
6954 if ( u_int->second._coincides ) continue;
6955 double dot = u_int->second._faceNorm * line.Direction();
6956 if ( dot > maxDot ) maxDot = dot;
6957 if ( dot < minDot ) minDot = dot;
6959 touchingInt = ( minDot*maxDot < 0 );
6964 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6975 u_int1 = u_int2; // to next intersection
6977 } // loop on intersections with one line
6981 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6984 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6987 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6988 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6990 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6993 if ( (f<0) == (l<0) )
6996 if ( hasPositionInfo )
6997 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6999 } // loop on intersections of the tree lines - thorough analysis
7001 if ( !hasPositionInfo )
7003 // gather info on faces position - is face in the outer boundary or not
7004 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7005 findOuterBoundary( u2inters.begin()->second._face );
7008 } // two attempts - with and w/o faces position info in the mesh
7010 return TopAbs_UNKNOWN;
7013 //=======================================================================
7015 * \brief Return elements possibly intersecting the line
7017 //=======================================================================
7019 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7020 SMDSAbs_ElementType type,
7021 vector< const SMDS_MeshElement* >& foundElems)
7023 if ( !_ebbTree || _elementType != type )
7025 if ( _ebbTree ) delete _ebbTree;
7026 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7028 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7029 _ebbTree->getElementsNearLine( line, suspectFaces );
7030 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7033 //=======================================================================
7035 * \brief Return SMESH_ElementSearcher
7037 //=======================================================================
7039 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7041 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7044 //=======================================================================
7046 * \brief Return SMESH_ElementSearcher
7048 //=======================================================================
7050 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7052 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7055 //=======================================================================
7057 * \brief Return true if the point is IN or ON of the element
7059 //=======================================================================
7061 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7063 if ( element->GetType() == SMDSAbs_Volume)
7065 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7068 // get ordered nodes
7070 vector< gp_XYZ > xyz;
7071 vector<const SMDS_MeshNode*> nodeList;
7073 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7074 if ( element->IsQuadratic() ) {
7075 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7076 nodeIt = f->interlacedNodesElemIterator();
7077 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7078 nodeIt = e->interlacedNodesElemIterator();
7080 while ( nodeIt->more() )
7082 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7083 xyz.push_back( SMESH_TNodeXYZ(node) );
7084 nodeList.push_back(node);
7087 int i, nbNodes = element->NbNodes();
7089 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7091 // compute face normal
7092 gp_Vec faceNorm(0,0,0);
7093 xyz.push_back( xyz.front() );
7094 nodeList.push_back( nodeList.front() );
7095 for ( i = 0; i < nbNodes; ++i )
7097 gp_Vec edge1( xyz[i+1], xyz[i]);
7098 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7099 faceNorm += edge1 ^ edge2;
7101 double normSize = faceNorm.Magnitude();
7102 if ( normSize <= tol )
7104 // degenerated face: point is out if it is out of all face edges
7105 for ( i = 0; i < nbNodes; ++i )
7107 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7108 if ( !isOut( &edge, point, tol ))
7113 faceNorm /= normSize;
7115 // check if the point lays on face plane
7116 gp_Vec n2p( xyz[0], point );
7117 if ( fabs( n2p * faceNorm ) > tol )
7118 return true; // not on face plane
7120 // check if point is out of face boundary:
7121 // define it by closest transition of a ray point->infinity through face boundary
7122 // on the face plane.
7123 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7124 // to find intersections of the ray with the boundary.
7126 gp_Vec plnNorm = ray ^ faceNorm;
7127 normSize = plnNorm.Magnitude();
7128 if ( normSize <= tol ) return false; // point coincides with the first node
7129 plnNorm /= normSize;
7130 // for each node of the face, compute its signed distance to the plane
7131 vector<double> dist( nbNodes + 1);
7132 for ( i = 0; i < nbNodes; ++i )
7134 gp_Vec n2p( xyz[i], point );
7135 dist[i] = n2p * plnNorm;
7137 dist.back() = dist.front();
7138 // find the closest intersection
7140 double rClosest, distClosest = 1e100;;
7142 for ( i = 0; i < nbNodes; ++i )
7145 if ( fabs( dist[i]) < tol )
7147 else if ( fabs( dist[i+1]) < tol )
7149 else if ( dist[i] * dist[i+1] < 0 )
7150 r = dist[i] / ( dist[i] - dist[i+1] );
7152 continue; // no intersection
7153 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7154 gp_Vec p2int ( point, pInt);
7155 if ( p2int * ray > -tol ) // right half-space
7157 double intDist = p2int.SquareMagnitude();
7158 if ( intDist < distClosest )
7163 distClosest = intDist;
7168 return true; // no intesections - out
7170 // analyse transition
7171 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7172 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7173 gp_Vec p2int ( point, pClosest );
7174 bool out = (edgeNorm * p2int) < -tol;
7175 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7178 // ray pass through a face node; analyze transition through an adjacent edge
7179 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7180 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7181 gp_Vec edgeAdjacent( p1, p2 );
7182 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7183 bool out2 = (edgeNorm2 * p2int) < -tol;
7185 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7186 return covexCorner ? (out || out2) : (out && out2);
7188 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7190 // point is out of edge if it is NOT ON any straight part of edge
7191 // (we consider quadratic edge as being composed of two straight parts)
7192 for ( i = 1; i < nbNodes; ++i )
7194 gp_Vec edge( xyz[i-1], xyz[i]);
7195 gp_Vec n1p ( xyz[i-1], point);
7196 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7199 gp_Vec n2p( xyz[i], point );
7200 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7202 return false; // point is ON this part
7206 // Node or 0D element -------------------------------------------------------------------------
7208 gp_Vec n2p ( xyz[0], point );
7209 return n2p.Magnitude() <= tol;
7214 //=======================================================================
7215 //function : SimplifyFace
7217 //=======================================================================
7218 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7219 vector<const SMDS_MeshNode *>& poly_nodes,
7220 vector<int>& quantities) const
7222 int nbNodes = faceNodes.size();
7227 set<const SMDS_MeshNode*> nodeSet;
7229 // get simple seq of nodes
7230 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7231 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7232 int iSimple = 0, nbUnique = 0;
7234 simpleNodes[iSimple++] = faceNodes[0];
7236 for (int iCur = 1; iCur < nbNodes; iCur++) {
7237 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7238 simpleNodes[iSimple++] = faceNodes[iCur];
7239 if (nodeSet.insert( faceNodes[iCur] ).second)
7243 int nbSimple = iSimple;
7244 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7254 bool foundLoop = (nbSimple > nbUnique);
7257 set<const SMDS_MeshNode*> loopSet;
7258 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7259 const SMDS_MeshNode* n = simpleNodes[iSimple];
7260 if (!loopSet.insert( n ).second) {
7264 int iC = 0, curLast = iSimple;
7265 for (; iC < curLast; iC++) {
7266 if (simpleNodes[iC] == n) break;
7268 int loopLen = curLast - iC;
7270 // create sub-element
7272 quantities.push_back(loopLen);
7273 for (; iC < curLast; iC++) {
7274 poly_nodes.push_back(simpleNodes[iC]);
7277 // shift the rest nodes (place from the first loop position)
7278 for (iC = curLast + 1; iC < nbSimple; iC++) {
7279 simpleNodes[iC - loopLen] = simpleNodes[iC];
7281 nbSimple -= loopLen;
7284 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7285 } // while (foundLoop)
7289 quantities.push_back(iSimple);
7290 for (int i = 0; i < iSimple; i++)
7291 poly_nodes.push_back(simpleNodes[i]);
7297 //=======================================================================
7298 //function : MergeNodes
7299 //purpose : In each group, the cdr of nodes are substituted by the first one
7301 //=======================================================================
7303 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7305 MESSAGE("MergeNodes");
7306 myLastCreatedElems.Clear();
7307 myLastCreatedNodes.Clear();
7309 SMESHDS_Mesh* aMesh = GetMeshDS();
7311 TNodeNodeMap nodeNodeMap; // node to replace - new node
7312 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7313 list< int > rmElemIds, rmNodeIds;
7315 // Fill nodeNodeMap and elems
7317 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7318 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7319 list<const SMDS_MeshNode*>& nodes = *grIt;
7320 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7321 const SMDS_MeshNode* nToKeep = *nIt;
7322 //MESSAGE("node to keep " << nToKeep->GetID());
7323 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7324 const SMDS_MeshNode* nToRemove = *nIt;
7325 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7326 if ( nToRemove != nToKeep ) {
7327 //MESSAGE(" node to remove " << nToRemove->GetID());
7328 rmNodeIds.push_back( nToRemove->GetID() );
7329 AddToSameGroups( nToKeep, nToRemove, aMesh );
7332 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7333 while ( invElemIt->more() ) {
7334 const SMDS_MeshElement* elem = invElemIt->next();
7339 // Change element nodes or remove an element
7341 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7342 for ( ; eIt != elems.end(); eIt++ ) {
7343 const SMDS_MeshElement* elem = *eIt;
7344 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7345 int nbNodes = elem->NbNodes();
7346 int aShapeId = FindShape( elem );
7348 set<const SMDS_MeshNode*> nodeSet;
7349 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7350 int iUnique = 0, iCur = 0, nbRepl = 0;
7351 vector<int> iRepl( nbNodes );
7353 // get new seq of nodes
7354 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7355 while ( itN->more() ) {
7356 const SMDS_MeshNode* n =
7357 static_cast<const SMDS_MeshNode*>( itN->next() );
7359 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7360 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7362 // BUG 0020185: begin
7364 bool stopRecur = false;
7365 set<const SMDS_MeshNode*> nodesRecur;
7366 nodesRecur.insert(n);
7367 while (!stopRecur) {
7368 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7369 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7370 n = (*nnIt_i).second;
7371 if (!nodesRecur.insert(n).second) {
7372 // error: recursive dependancy
7381 iRepl[ nbRepl++ ] = iCur;
7383 curNodes[ iCur ] = n;
7384 bool isUnique = nodeSet.insert( n ).second;
7386 uniqueNodes[ iUnique++ ] = n;
7390 // Analyse element topology after replacement
7393 int nbUniqueNodes = nodeSet.size();
7394 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7395 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7396 // Polygons and Polyhedral volumes
7397 if (elem->IsPoly()) {
7399 if (elem->GetType() == SMDSAbs_Face) {
7401 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7403 for (; inode < nbNodes; inode++) {
7404 face_nodes[inode] = curNodes[inode];
7407 vector<const SMDS_MeshNode *> polygons_nodes;
7408 vector<int> quantities;
7409 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7412 for (int iface = 0; iface < nbNew; iface++) {
7413 int nbNodes = quantities[iface];
7414 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7415 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7416 poly_nodes[ii] = polygons_nodes[inode];
7418 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7419 myLastCreatedElems.Append(newElem);
7421 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7424 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7425 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7426 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7428 if (nbNew > 0) quid = nbNew - 1;
7429 vector<int> newquant(quantities.begin()+quid, quantities.end());
7430 const SMDS_MeshElement* newElem = 0;
7431 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7432 myLastCreatedElems.Append(newElem);
7433 if ( aShapeId && newElem )
7434 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7435 rmElemIds.push_back(elem->GetID());
7438 rmElemIds.push_back(elem->GetID());
7442 else if (elem->GetType() == SMDSAbs_Volume) {
7443 // Polyhedral volume
7444 if (nbUniqueNodes < 4) {
7445 rmElemIds.push_back(elem->GetID());
7448 // each face has to be analyzed in order to check volume validity
7449 const SMDS_VtkVolume* aPolyedre =
7450 dynamic_cast<const SMDS_VtkVolume*>( elem );
7452 int nbFaces = aPolyedre->NbFaces();
7454 vector<const SMDS_MeshNode *> poly_nodes;
7455 vector<int> quantities;
7457 for (int iface = 1; iface <= nbFaces; iface++) {
7458 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7459 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7461 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7462 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7463 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7464 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7465 faceNode = (*nnIt).second;
7467 faceNodes[inode - 1] = faceNode;
7470 SimplifyFace(faceNodes, poly_nodes, quantities);
7473 if (quantities.size() > 3) {
7474 // to be done: remove coincident faces
7477 if (quantities.size() > 3)
7479 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7480 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7481 const SMDS_MeshElement* newElem = 0;
7482 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7483 myLastCreatedElems.Append(newElem);
7484 if ( aShapeId && newElem )
7485 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7486 rmElemIds.push_back(elem->GetID());
7490 rmElemIds.push_back(elem->GetID());
7501 // TODO not all the possible cases are solved. Find something more generic?
7502 switch ( nbNodes ) {
7503 case 2: ///////////////////////////////////// EDGE
7504 isOk = false; break;
7505 case 3: ///////////////////////////////////// TRIANGLE
7506 isOk = false; break;
7508 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7510 else { //////////////////////////////////// QUADRANGLE
7511 if ( nbUniqueNodes < 3 )
7513 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7514 isOk = false; // opposite nodes stick
7515 //MESSAGE("isOk " << isOk);
7518 case 6: ///////////////////////////////////// PENTAHEDRON
7519 if ( nbUniqueNodes == 4 ) {
7520 // ---------------------------------> tetrahedron
7522 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7523 // all top nodes stick: reverse a bottom
7524 uniqueNodes[ 0 ] = curNodes [ 1 ];
7525 uniqueNodes[ 1 ] = curNodes [ 0 ];
7527 else if (nbRepl == 3 &&
7528 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7529 // all bottom nodes stick: set a top before
7530 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7531 uniqueNodes[ 0 ] = curNodes [ 3 ];
7532 uniqueNodes[ 1 ] = curNodes [ 4 ];
7533 uniqueNodes[ 2 ] = curNodes [ 5 ];
7535 else if (nbRepl == 4 &&
7536 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7537 // a lateral face turns into a line: reverse a bottom
7538 uniqueNodes[ 0 ] = curNodes [ 1 ];
7539 uniqueNodes[ 1 ] = curNodes [ 0 ];
7544 else if ( nbUniqueNodes == 5 ) {
7545 // PENTAHEDRON --------------------> 2 tetrahedrons
7546 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7547 // a bottom node sticks with a linked top one
7549 SMDS_MeshElement* newElem =
7550 aMesh->AddVolume(curNodes[ 3 ],
7553 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7554 myLastCreatedElems.Append(newElem);
7556 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7557 // 2. : reverse a bottom
7558 uniqueNodes[ 0 ] = curNodes [ 1 ];
7559 uniqueNodes[ 1 ] = curNodes [ 0 ];
7569 if(elem->IsQuadratic()) { // Quadratic quadrangle
7581 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7584 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7586 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7587 uniqueNodes[0] = curNodes[0];
7588 uniqueNodes[1] = curNodes[2];
7589 uniqueNodes[2] = curNodes[3];
7590 uniqueNodes[3] = curNodes[5];
7591 uniqueNodes[4] = curNodes[6];
7592 uniqueNodes[5] = curNodes[7];
7595 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7596 uniqueNodes[0] = curNodes[0];
7597 uniqueNodes[1] = curNodes[1];
7598 uniqueNodes[2] = curNodes[2];
7599 uniqueNodes[3] = curNodes[4];
7600 uniqueNodes[4] = curNodes[5];
7601 uniqueNodes[5] = curNodes[6];
7604 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7605 uniqueNodes[0] = curNodes[1];
7606 uniqueNodes[1] = curNodes[2];
7607 uniqueNodes[2] = curNodes[3];
7608 uniqueNodes[3] = curNodes[5];
7609 uniqueNodes[4] = curNodes[6];
7610 uniqueNodes[5] = curNodes[0];
7613 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7614 uniqueNodes[0] = curNodes[0];
7615 uniqueNodes[1] = curNodes[1];
7616 uniqueNodes[2] = curNodes[3];
7617 uniqueNodes[3] = curNodes[4];
7618 uniqueNodes[4] = curNodes[6];
7619 uniqueNodes[5] = curNodes[7];
7622 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7623 uniqueNodes[0] = curNodes[0];
7624 uniqueNodes[1] = curNodes[2];
7625 uniqueNodes[2] = curNodes[3];
7626 uniqueNodes[3] = curNodes[1];
7627 uniqueNodes[4] = curNodes[6];
7628 uniqueNodes[5] = curNodes[7];
7631 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7632 uniqueNodes[0] = curNodes[0];
7633 uniqueNodes[1] = curNodes[1];
7634 uniqueNodes[2] = curNodes[2];
7635 uniqueNodes[3] = curNodes[4];
7636 uniqueNodes[4] = curNodes[5];
7637 uniqueNodes[5] = curNodes[7];
7640 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7641 uniqueNodes[0] = curNodes[0];
7642 uniqueNodes[1] = curNodes[1];
7643 uniqueNodes[2] = curNodes[3];
7644 uniqueNodes[3] = curNodes[4];
7645 uniqueNodes[4] = curNodes[2];
7646 uniqueNodes[5] = curNodes[7];
7649 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7650 uniqueNodes[0] = curNodes[0];
7651 uniqueNodes[1] = curNodes[1];
7652 uniqueNodes[2] = curNodes[2];
7653 uniqueNodes[3] = curNodes[4];
7654 uniqueNodes[4] = curNodes[5];
7655 uniqueNodes[5] = curNodes[3];
7660 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7663 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7667 //////////////////////////////////// HEXAHEDRON
7669 SMDS_VolumeTool hexa (elem);
7670 hexa.SetExternalNormal();
7671 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7672 //////////////////////// ---> tetrahedron
7673 for ( int iFace = 0; iFace < 6; iFace++ ) {
7674 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7675 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7676 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7677 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7678 // one face turns into a point ...
7679 int iOppFace = hexa.GetOppFaceIndex( iFace );
7680 ind = hexa.GetFaceNodesIndices( iOppFace );
7682 iUnique = 2; // reverse a tetrahedron bottom
7683 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7684 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7686 else if ( iUnique >= 0 )
7687 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7689 if ( nbStick == 1 ) {
7690 // ... and the opposite one - into a triangle.
7692 ind = hexa.GetFaceNodesIndices( iFace );
7693 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7700 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7701 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7702 for ( int iFace = 0; iFace < 6; iFace++ ) {
7703 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7704 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7705 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7706 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7707 // one face turns into a point ...
7708 int iOppFace = hexa.GetOppFaceIndex( iFace );
7709 ind = hexa.GetFaceNodesIndices( iOppFace );
7711 iUnique = 2; // reverse a tetrahedron 1 bottom
7712 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7713 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7715 else if ( iUnique >= 0 )
7716 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7718 if ( nbStick == 0 ) {
7719 // ... and the opposite one is a quadrangle
7721 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7722 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7725 SMDS_MeshElement* newElem =
7726 aMesh->AddVolume(curNodes[ind[ 0 ]],
7729 curNodes[indTop[ 0 ]]);
7730 myLastCreatedElems.Append(newElem);
7732 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7739 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7740 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7741 // find indices of quad and tri faces
7742 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7743 for ( iFace = 0; iFace < 6; iFace++ ) {
7744 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7746 for ( iCur = 0; iCur < 4; iCur++ )
7747 nodeSet.insert( curNodes[ind[ iCur ]] );
7748 nbUniqueNodes = nodeSet.size();
7749 if ( nbUniqueNodes == 3 )
7750 iTriFace[ nbTri++ ] = iFace;
7751 else if ( nbUniqueNodes == 4 )
7752 iQuadFace[ nbQuad++ ] = iFace;
7754 if (nbQuad == 2 && nbTri == 4 &&
7755 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7756 // 2 opposite quadrangles stuck with a diagonal;
7757 // sample groups of merged indices: (0-4)(2-6)
7758 // --------------------------------------------> 2 tetrahedrons
7759 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7760 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7761 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7762 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7763 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7764 // stuck with 0-2 diagonal
7772 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7773 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7774 // stuck with 1-3 diagonal
7786 uniqueNodes[ 0 ] = curNodes [ i0 ];
7787 uniqueNodes[ 1 ] = curNodes [ i1d ];
7788 uniqueNodes[ 2 ] = curNodes [ i3d ];
7789 uniqueNodes[ 3 ] = curNodes [ i0t ];
7792 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7796 myLastCreatedElems.Append(newElem);
7798 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7801 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7802 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7803 // --------------------------------------------> prism
7804 // find 2 opposite triangles
7806 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7807 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7808 // find indices of kept and replaced nodes
7809 // and fill unique nodes of 2 opposite triangles
7810 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7811 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7812 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7813 // fill unique nodes
7816 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7817 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7818 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7820 // iCur of a linked node of the opposite face (make normals co-directed):
7821 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7822 // check that correspondent corners of triangles are linked
7823 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7826 uniqueNodes[ iUnique ] = n;
7827 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7836 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7842 } // switch ( nbNodes )
7844 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7847 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7848 // Change nodes of polyedre
7849 const SMDS_VtkVolume* aPolyedre =
7850 dynamic_cast<const SMDS_VtkVolume*>( elem );
7852 int nbFaces = aPolyedre->NbFaces();
7854 vector<const SMDS_MeshNode *> poly_nodes;
7855 vector<int> quantities (nbFaces);
7857 for (int iface = 1; iface <= nbFaces; iface++) {
7858 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7859 quantities[iface - 1] = nbFaceNodes;
7861 for (inode = 1; inode <= nbFaceNodes; inode++) {
7862 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7864 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7865 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7866 curNode = (*nnIt).second;
7868 poly_nodes.push_back(curNode);
7871 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7875 //int elemId = elem->GetID();
7876 //MESSAGE("Change regular element or polygon " << elemId);
7877 SMDSAbs_ElementType etyp = elem->GetType();
7878 uniqueNodes.resize(nbUniqueNodes);
7879 SMDS_MeshElement* newElem = 0;
7880 if (elem->GetEntityType() == SMDSEntity_Polygon)
7881 newElem = this->AddElement(uniqueNodes, etyp, true);
7883 newElem = this->AddElement(uniqueNodes, etyp, false);
7886 myLastCreatedElems.Append(newElem);
7888 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7890 aMesh->RemoveElement(elem);
7894 // Remove invalid regular element or invalid polygon
7895 //MESSAGE("Remove invalid " << elem->GetID());
7896 rmElemIds.push_back( elem->GetID() );
7899 } // loop on elements
7901 // Remove bad elements, then equal nodes (order important)
7903 Remove( rmElemIds, false );
7904 Remove( rmNodeIds, true );
7909 // ========================================================
7910 // class : SortableElement
7911 // purpose : allow sorting elements basing on their nodes
7912 // ========================================================
7913 class SortableElement : public set <const SMDS_MeshElement*>
7917 SortableElement( const SMDS_MeshElement* theElem )
7920 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7921 while ( nodeIt->more() )
7922 this->insert( nodeIt->next() );
7925 const SMDS_MeshElement* Get() const
7928 void Set(const SMDS_MeshElement* e) const
7933 mutable const SMDS_MeshElement* myElem;
7936 //=======================================================================
7937 //function : FindEqualElements
7938 //purpose : Return list of group of elements built on the same nodes.
7939 // Search among theElements or in the whole mesh if theElements is empty
7940 //=======================================================================
7941 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7942 TListOfListOfElementsID & theGroupsOfElementsID)
7944 myLastCreatedElems.Clear();
7945 myLastCreatedNodes.Clear();
7947 typedef set<const SMDS_MeshElement*> TElemsSet;
7948 typedef map< SortableElement, int > TMapOfNodeSet;
7949 typedef list<int> TGroupOfElems;
7952 if ( theElements.empty() )
7953 { // get all elements in the mesh
7954 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7955 while ( eIt->more() )
7956 elems.insert( elems.end(), eIt->next());
7959 elems = theElements;
7961 vector< TGroupOfElems > arrayOfGroups;
7962 TGroupOfElems groupOfElems;
7963 TMapOfNodeSet mapOfNodeSet;
7965 TElemsSet::iterator elemIt = elems.begin();
7966 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7967 const SMDS_MeshElement* curElem = *elemIt;
7968 SortableElement SE(curElem);
7971 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7972 if( !(pp.second) ) {
7973 TMapOfNodeSet::iterator& itSE = pp.first;
7974 ind = (*itSE).second;
7975 arrayOfGroups[ind].push_back(curElem->GetID());
7978 groupOfElems.clear();
7979 groupOfElems.push_back(curElem->GetID());
7980 arrayOfGroups.push_back(groupOfElems);
7985 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7986 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7987 groupOfElems = *groupIt;
7988 if ( groupOfElems.size() > 1 ) {
7989 groupOfElems.sort();
7990 theGroupsOfElementsID.push_back(groupOfElems);
7995 //=======================================================================
7996 //function : MergeElements
7997 //purpose : In each given group, substitute all elements by the first one.
7998 //=======================================================================
8000 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8002 myLastCreatedElems.Clear();
8003 myLastCreatedNodes.Clear();
8005 typedef list<int> TListOfIDs;
8006 TListOfIDs rmElemIds; // IDs of elems to remove
8008 SMESHDS_Mesh* aMesh = GetMeshDS();
8010 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8011 while ( groupsIt != theGroupsOfElementsID.end() ) {
8012 TListOfIDs& aGroupOfElemID = *groupsIt;
8013 aGroupOfElemID.sort();
8014 int elemIDToKeep = aGroupOfElemID.front();
8015 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8016 aGroupOfElemID.pop_front();
8017 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8018 while ( idIt != aGroupOfElemID.end() ) {
8019 int elemIDToRemove = *idIt;
8020 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8021 // add the kept element in groups of removed one (PAL15188)
8022 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8023 rmElemIds.push_back( elemIDToRemove );
8029 Remove( rmElemIds, false );
8032 //=======================================================================
8033 //function : MergeEqualElements
8034 //purpose : Remove all but one of elements built on the same nodes.
8035 //=======================================================================
8037 void SMESH_MeshEditor::MergeEqualElements()
8039 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8040 to merge equal elements in the whole mesh */
8041 TListOfListOfElementsID aGroupsOfElementsID;
8042 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8043 MergeElements(aGroupsOfElementsID);
8046 //=======================================================================
8047 //function : FindFaceInSet
8048 //purpose : Return a face having linked nodes n1 and n2 and which is
8049 // - not in avoidSet,
8050 // - in elemSet provided that !elemSet.empty()
8051 // i1 and i2 optionally returns indices of n1 and n2
8052 //=======================================================================
8054 const SMDS_MeshElement*
8055 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8056 const SMDS_MeshNode* n2,
8057 const TIDSortedElemSet& elemSet,
8058 const TIDSortedElemSet& avoidSet,
8064 const SMDS_MeshElement* face = 0;
8066 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8067 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8068 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8070 //MESSAGE("in while ( invElemIt->more() && !face )");
8071 const SMDS_MeshElement* elem = invElemIt->next();
8072 if (avoidSet.count( elem ))
8074 if ( !elemSet.empty() && !elemSet.count( elem ))
8077 i1 = elem->GetNodeIndex( n1 );
8078 // find a n2 linked to n1
8079 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8080 for ( int di = -1; di < 2 && !face; di += 2 )
8082 i2 = (i1+di+nbN) % nbN;
8083 if ( elem->GetNode( i2 ) == n2 )
8086 if ( !face && elem->IsQuadratic())
8088 // analysis for quadratic elements using all nodes
8089 const SMDS_VtkFace* F =
8090 dynamic_cast<const SMDS_VtkFace*>(elem);
8091 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8092 // use special nodes iterator
8093 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8094 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8095 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8097 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8098 if ( n1 == prevN && n2 == n )
8102 else if ( n2 == prevN && n1 == n )
8104 face = elem; swap( i1, i2 );
8110 if ( n1ind ) *n1ind = i1;
8111 if ( n2ind ) *n2ind = i2;
8115 //=======================================================================
8116 //function : findAdjacentFace
8118 //=======================================================================
8120 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8121 const SMDS_MeshNode* n2,
8122 const SMDS_MeshElement* elem)
8124 TIDSortedElemSet elemSet, avoidSet;
8126 avoidSet.insert ( elem );
8127 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8130 //=======================================================================
8131 //function : FindFreeBorder
8133 //=======================================================================
8135 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8137 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8138 const SMDS_MeshNode* theSecondNode,
8139 const SMDS_MeshNode* theLastNode,
8140 list< const SMDS_MeshNode* > & theNodes,
8141 list< const SMDS_MeshElement* >& theFaces)
8143 if ( !theFirstNode || !theSecondNode )
8145 // find border face between theFirstNode and theSecondNode
8146 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8150 theFaces.push_back( curElem );
8151 theNodes.push_back( theFirstNode );
8152 theNodes.push_back( theSecondNode );
8154 //vector<const SMDS_MeshNode*> nodes;
8155 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8156 TIDSortedElemSet foundElems;
8157 bool needTheLast = ( theLastNode != 0 );
8159 while ( nStart != theLastNode ) {
8160 if ( nStart == theFirstNode )
8161 return !needTheLast;
8163 // find all free border faces sharing form nStart
8165 list< const SMDS_MeshElement* > curElemList;
8166 list< const SMDS_MeshNode* > nStartList;
8167 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8168 while ( invElemIt->more() ) {
8169 const SMDS_MeshElement* e = invElemIt->next();
8170 if ( e == curElem || foundElems.insert( e ).second ) {
8172 int iNode = 0, nbNodes = e->NbNodes();
8173 //const SMDS_MeshNode* nodes[nbNodes+1];
8174 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8176 if(e->IsQuadratic()) {
8177 const SMDS_VtkFace* F =
8178 dynamic_cast<const SMDS_VtkFace*>(e);
8179 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8180 // use special nodes iterator
8181 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8182 while( anIter->more() ) {
8183 nodes[ iNode++ ] = cast2Node(anIter->next());
8187 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8188 while ( nIt->more() )
8189 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8191 nodes[ iNode ] = nodes[ 0 ];
8193 for ( iNode = 0; iNode < nbNodes; iNode++ )
8194 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8195 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8196 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8198 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8199 curElemList.push_back( e );
8203 // analyse the found
8205 int nbNewBorders = curElemList.size();
8206 if ( nbNewBorders == 0 ) {
8207 // no free border furthermore
8208 return !needTheLast;
8210 else if ( nbNewBorders == 1 ) {
8211 // one more element found
8213 nStart = nStartList.front();
8214 curElem = curElemList.front();
8215 theFaces.push_back( curElem );
8216 theNodes.push_back( nStart );
8219 // several continuations found
8220 list< const SMDS_MeshElement* >::iterator curElemIt;
8221 list< const SMDS_MeshNode* >::iterator nStartIt;
8222 // check if one of them reached the last node
8223 if ( needTheLast ) {
8224 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8225 curElemIt!= curElemList.end();
8226 curElemIt++, nStartIt++ )
8227 if ( *nStartIt == theLastNode ) {
8228 theFaces.push_back( *curElemIt );
8229 theNodes.push_back( *nStartIt );
8233 // find the best free border by the continuations
8234 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8235 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8236 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8237 curElemIt!= curElemList.end();
8238 curElemIt++, nStartIt++ )
8240 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8241 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8242 // find one more free border
8243 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8247 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8248 // choice: clear a worse one
8249 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8250 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8251 contNodes[ iWorse ].clear();
8252 contFaces[ iWorse ].clear();
8255 if ( contNodes[0].empty() && contNodes[1].empty() )
8258 // append the best free border
8259 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8260 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8261 theNodes.pop_back(); // remove nIgnore
8262 theNodes.pop_back(); // remove nStart
8263 theFaces.pop_back(); // remove curElem
8264 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8265 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8266 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8267 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8270 } // several continuations found
8271 } // while ( nStart != theLastNode )
8276 //=======================================================================
8277 //function : CheckFreeBorderNodes
8278 //purpose : Return true if the tree nodes are on a free border
8279 //=======================================================================
8281 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8282 const SMDS_MeshNode* theNode2,
8283 const SMDS_MeshNode* theNode3)
8285 list< const SMDS_MeshNode* > nodes;
8286 list< const SMDS_MeshElement* > faces;
8287 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8290 //=======================================================================
8291 //function : SewFreeBorder
8293 //=======================================================================
8295 SMESH_MeshEditor::Sew_Error
8296 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8297 const SMDS_MeshNode* theBordSecondNode,
8298 const SMDS_MeshNode* theBordLastNode,
8299 const SMDS_MeshNode* theSideFirstNode,
8300 const SMDS_MeshNode* theSideSecondNode,
8301 const SMDS_MeshNode* theSideThirdNode,
8302 const bool theSideIsFreeBorder,
8303 const bool toCreatePolygons,
8304 const bool toCreatePolyedrs)
8306 myLastCreatedElems.Clear();
8307 myLastCreatedNodes.Clear();
8309 MESSAGE("::SewFreeBorder()");
8310 Sew_Error aResult = SEW_OK;
8312 // ====================================
8313 // find side nodes and elements
8314 // ====================================
8316 list< const SMDS_MeshNode* > nSide[ 2 ];
8317 list< const SMDS_MeshElement* > eSide[ 2 ];
8318 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8319 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8323 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8324 nSide[0], eSide[0])) {
8325 MESSAGE(" Free Border 1 not found " );
8326 aResult = SEW_BORDER1_NOT_FOUND;
8328 if (theSideIsFreeBorder) {
8331 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8332 nSide[1], eSide[1])) {
8333 MESSAGE(" Free Border 2 not found " );
8334 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8337 if ( aResult != SEW_OK )
8340 if (!theSideIsFreeBorder) {
8344 // -------------------------------------------------------------------------
8346 // 1. If nodes to merge are not coincident, move nodes of the free border
8347 // from the coord sys defined by the direction from the first to last
8348 // nodes of the border to the correspondent sys of the side 2
8349 // 2. On the side 2, find the links most co-directed with the correspondent
8350 // links of the free border
8351 // -------------------------------------------------------------------------
8353 // 1. Since sewing may break if there are volumes to split on the side 2,
8354 // we wont move nodes but just compute new coordinates for them
8355 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8356 TNodeXYZMap nBordXYZ;
8357 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8358 list< const SMDS_MeshNode* >::iterator nBordIt;
8360 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8361 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8362 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8363 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8364 double tol2 = 1.e-8;
8365 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8366 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8367 // Need node movement.
8369 // find X and Z axes to create trsf
8370 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8372 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8374 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8377 gp_Ax3 toBordAx( Pb1, Zb, X );
8378 gp_Ax3 fromSideAx( Ps1, Zs, X );
8379 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8381 gp_Trsf toBordSys, fromSide2Sys;
8382 toBordSys.SetTransformation( toBordAx );
8383 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8384 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8387 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8388 const SMDS_MeshNode* n = *nBordIt;
8389 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8390 toBordSys.Transforms( xyz );
8391 fromSide2Sys.Transforms( xyz );
8392 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8396 // just insert nodes XYZ in the nBordXYZ map
8397 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8398 const SMDS_MeshNode* n = *nBordIt;
8399 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8403 // 2. On the side 2, find the links most co-directed with the correspondent
8404 // links of the free border
8406 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8407 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8408 sideNodes.push_back( theSideFirstNode );
8410 bool hasVolumes = false;
8411 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8412 set<long> foundSideLinkIDs, checkedLinkIDs;
8413 SMDS_VolumeTool volume;
8414 //const SMDS_MeshNode* faceNodes[ 4 ];
8416 const SMDS_MeshNode* sideNode;
8417 const SMDS_MeshElement* sideElem;
8418 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8419 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8420 nBordIt = bordNodes.begin();
8422 // border node position and border link direction to compare with
8423 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8424 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8425 // choose next side node by link direction or by closeness to
8426 // the current border node:
8427 bool searchByDir = ( *nBordIt != theBordLastNode );
8429 // find the next node on the Side 2
8431 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8433 checkedLinkIDs.clear();
8434 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8436 // loop on inverse elements of current node (prevSideNode) on the Side 2
8437 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8438 while ( invElemIt->more() )
8440 const SMDS_MeshElement* elem = invElemIt->next();
8441 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8442 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8443 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8444 bool isVolume = volume.Set( elem );
8445 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8446 if ( isVolume ) // --volume
8448 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8449 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8450 if(elem->IsQuadratic()) {
8451 const SMDS_VtkFace* F =
8452 dynamic_cast<const SMDS_VtkFace*>(elem);
8453 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8454 // use special nodes iterator
8455 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8456 while( anIter->more() ) {
8457 nodes[ iNode ] = cast2Node(anIter->next());
8458 if ( nodes[ iNode++ ] == prevSideNode )
8459 iPrevNode = iNode - 1;
8463 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8464 while ( nIt->more() ) {
8465 nodes[ iNode ] = cast2Node( nIt->next() );
8466 if ( nodes[ iNode++ ] == prevSideNode )
8467 iPrevNode = iNode - 1;
8470 // there are 2 links to check
8475 // loop on links, to be precise, on the second node of links
8476 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8477 const SMDS_MeshNode* n = nodes[ iNode ];
8479 if ( !volume.IsLinked( n, prevSideNode ))
8483 if ( iNode ) // a node before prevSideNode
8484 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8485 else // a node after prevSideNode
8486 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8488 // check if this link was already used
8489 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8490 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8491 if (!isJustChecked &&
8492 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8494 // test a link geometrically
8495 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8496 bool linkIsBetter = false;
8497 double dot = 0.0, dist = 0.0;
8498 if ( searchByDir ) { // choose most co-directed link
8499 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8500 linkIsBetter = ( dot > maxDot );
8502 else { // choose link with the node closest to bordPos
8503 dist = ( nextXYZ - bordPos ).SquareModulus();
8504 linkIsBetter = ( dist < minDist );
8506 if ( linkIsBetter ) {
8515 } // loop on inverse elements of prevSideNode
8518 MESSAGE(" Cant find path by links of the Side 2 ");
8519 return SEW_BAD_SIDE_NODES;
8521 sideNodes.push_back( sideNode );
8522 sideElems.push_back( sideElem );
8523 foundSideLinkIDs.insert ( linkID );
8524 prevSideNode = sideNode;
8526 if ( *nBordIt == theBordLastNode )
8527 searchByDir = false;
8529 // find the next border link to compare with
8530 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8531 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8532 // move to next border node if sideNode is before forward border node (bordPos)
8533 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8534 prevBordNode = *nBordIt;
8536 bordPos = nBordXYZ[ *nBordIt ];
8537 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8538 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8542 while ( sideNode != theSideSecondNode );
8544 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8545 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8546 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8548 } // end nodes search on the side 2
8550 // ============================
8551 // sew the border to the side 2
8552 // ============================
8554 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8555 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8557 TListOfListOfNodes nodeGroupsToMerge;
8558 if ( nbNodes[0] == nbNodes[1] ||
8559 ( theSideIsFreeBorder && !theSideThirdNode)) {
8561 // all nodes are to be merged
8563 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8564 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8565 nIt[0]++, nIt[1]++ )
8567 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8568 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8569 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8574 // insert new nodes into the border and the side to get equal nb of segments
8576 // get normalized parameters of nodes on the borders
8577 //double param[ 2 ][ maxNbNodes ];
8579 param[0] = new double [ maxNbNodes ];
8580 param[1] = new double [ maxNbNodes ];
8582 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8583 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8584 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8585 const SMDS_MeshNode* nPrev = *nIt;
8586 double bordLength = 0;
8587 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8588 const SMDS_MeshNode* nCur = *nIt;
8589 gp_XYZ segment (nCur->X() - nPrev->X(),
8590 nCur->Y() - nPrev->Y(),
8591 nCur->Z() - nPrev->Z());
8592 double segmentLen = segment.Modulus();
8593 bordLength += segmentLen;
8594 param[ iBord ][ iNode ] = bordLength;
8597 // normalize within [0,1]
8598 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8599 param[ iBord ][ iNode ] /= bordLength;
8603 // loop on border segments
8604 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8605 int i[ 2 ] = { 0, 0 };
8606 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8607 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8609 TElemOfNodeListMap insertMap;
8610 TElemOfNodeListMap::iterator insertMapIt;
8612 // key: elem to insert nodes into
8613 // value: 2 nodes to insert between + nodes to be inserted
8615 bool next[ 2 ] = { false, false };
8617 // find min adjacent segment length after sewing
8618 double nextParam = 10., prevParam = 0;
8619 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8620 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8621 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8622 if ( i[ iBord ] > 0 )
8623 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8625 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8626 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8627 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8629 // choose to insert or to merge nodes
8630 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8631 if ( Abs( du ) <= minSegLen * 0.2 ) {
8634 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8635 const SMDS_MeshNode* n0 = *nIt[0];
8636 const SMDS_MeshNode* n1 = *nIt[1];
8637 nodeGroupsToMerge.back().push_back( n1 );
8638 nodeGroupsToMerge.back().push_back( n0 );
8639 // position of node of the border changes due to merge
8640 param[ 0 ][ i[0] ] += du;
8641 // move n1 for the sake of elem shape evaluation during insertion.
8642 // n1 will be removed by MergeNodes() anyway
8643 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8644 next[0] = next[1] = true;
8649 int intoBord = ( du < 0 ) ? 0 : 1;
8650 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8651 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8652 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8653 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8654 if ( intoBord == 1 ) {
8655 // move node of the border to be on a link of elem of the side
8656 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8657 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8658 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8659 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8660 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8662 insertMapIt = insertMap.find( elem );
8663 bool notFound = ( insertMapIt == insertMap.end() );
8664 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8666 // insert into another link of the same element:
8667 // 1. perform insertion into the other link of the elem
8668 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8669 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8670 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8671 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8672 // 2. perform insertion into the link of adjacent faces
8674 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8676 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8680 if (toCreatePolyedrs) {
8681 // perform insertion into the links of adjacent volumes
8682 UpdateVolumes(n12, n22, nodeList);
8684 // 3. find an element appeared on n1 and n2 after the insertion
8685 insertMap.erase( elem );
8686 elem = findAdjacentFace( n1, n2, 0 );
8688 if ( notFound || otherLink ) {
8689 // add element and nodes of the side into the insertMap
8690 insertMapIt = insertMap.insert
8691 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8692 (*insertMapIt).second.push_back( n1 );
8693 (*insertMapIt).second.push_back( n2 );
8695 // add node to be inserted into elem
8696 (*insertMapIt).second.push_back( nIns );
8697 next[ 1 - intoBord ] = true;
8700 // go to the next segment
8701 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8702 if ( next[ iBord ] ) {
8703 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8705 nPrev[ iBord ] = *nIt[ iBord ];
8706 nIt[ iBord ]++; i[ iBord ]++;
8710 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8712 // perform insertion of nodes into elements
8714 for (insertMapIt = insertMap.begin();
8715 insertMapIt != insertMap.end();
8718 const SMDS_MeshElement* elem = (*insertMapIt).first;
8719 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8720 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8721 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8723 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8725 if ( !theSideIsFreeBorder ) {
8726 // look for and insert nodes into the faces adjacent to elem
8728 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8730 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8735 if (toCreatePolyedrs) {
8736 // perform insertion into the links of adjacent volumes
8737 UpdateVolumes(n1, n2, nodeList);
8743 } // end: insert new nodes
8745 MergeNodes ( nodeGroupsToMerge );
8750 //=======================================================================
8751 //function : InsertNodesIntoLink
8752 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8753 // and theBetweenNode2 and split theElement
8754 //=======================================================================
8756 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8757 const SMDS_MeshNode* theBetweenNode1,
8758 const SMDS_MeshNode* theBetweenNode2,
8759 list<const SMDS_MeshNode*>& theNodesToInsert,
8760 const bool toCreatePoly)
8762 if ( theFace->GetType() != SMDSAbs_Face ) return;
8764 // find indices of 2 link nodes and of the rest nodes
8765 int iNode = 0, il1, il2, i3, i4;
8766 il1 = il2 = i3 = i4 = -1;
8767 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8768 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8770 if(theFace->IsQuadratic()) {
8771 const SMDS_VtkFace* F =
8772 dynamic_cast<const SMDS_VtkFace*>(theFace);
8773 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8774 // use special nodes iterator
8775 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8776 while( anIter->more() ) {
8777 const SMDS_MeshNode* n = cast2Node(anIter->next());
8778 if ( n == theBetweenNode1 )
8780 else if ( n == theBetweenNode2 )
8786 nodes[ iNode++ ] = n;
8790 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8791 while ( nodeIt->more() ) {
8792 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8793 if ( n == theBetweenNode1 )
8795 else if ( n == theBetweenNode2 )
8801 nodes[ iNode++ ] = n;
8804 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8807 // arrange link nodes to go one after another regarding the face orientation
8808 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8809 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8814 aNodesToInsert.reverse();
8816 // check that not link nodes of a quadrangles are in good order
8817 int nbFaceNodes = theFace->NbNodes();
8818 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8824 if (toCreatePoly || theFace->IsPoly()) {
8827 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8829 // add nodes of face up to first node of link
8832 if(theFace->IsQuadratic()) {
8833 const SMDS_VtkFace* F =
8834 dynamic_cast<const SMDS_VtkFace*>(theFace);
8835 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8836 // use special nodes iterator
8837 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8838 while( anIter->more() && !isFLN ) {
8839 const SMDS_MeshNode* n = cast2Node(anIter->next());
8840 poly_nodes[iNode++] = n;
8841 if (n == nodes[il1]) {
8845 // add nodes to insert
8846 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8847 for (; nIt != aNodesToInsert.end(); nIt++) {
8848 poly_nodes[iNode++] = *nIt;
8850 // add nodes of face starting from last node of link
8851 while ( anIter->more() ) {
8852 poly_nodes[iNode++] = cast2Node(anIter->next());
8856 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8857 while ( nodeIt->more() && !isFLN ) {
8858 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8859 poly_nodes[iNode++] = n;
8860 if (n == nodes[il1]) {
8864 // add nodes to insert
8865 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8866 for (; nIt != aNodesToInsert.end(); nIt++) {
8867 poly_nodes[iNode++] = *nIt;
8869 // add nodes of face starting from last node of link
8870 while ( nodeIt->more() ) {
8871 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8872 poly_nodes[iNode++] = n;
8876 // edit or replace the face
8877 SMESHDS_Mesh *aMesh = GetMeshDS();
8879 if (theFace->IsPoly()) {
8880 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8883 int aShapeId = FindShape( theFace );
8885 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8886 myLastCreatedElems.Append(newElem);
8887 if ( aShapeId && newElem )
8888 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8890 aMesh->RemoveElement(theFace);
8895 SMESHDS_Mesh *aMesh = GetMeshDS();
8896 if( !theFace->IsQuadratic() ) {
8898 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8899 int nbLinkNodes = 2 + aNodesToInsert.size();
8900 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8901 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8902 linkNodes[ 0 ] = nodes[ il1 ];
8903 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8904 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8905 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8906 linkNodes[ iNode++ ] = *nIt;
8908 // decide how to split a quadrangle: compare possible variants
8909 // and choose which of splits to be a quadrangle
8910 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8911 if ( nbFaceNodes == 3 ) {
8912 iBestQuad = nbSplits;
8915 else if ( nbFaceNodes == 4 ) {
8916 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8917 double aBestRate = DBL_MAX;
8918 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8920 double aBadRate = 0;
8921 // evaluate elements quality
8922 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8923 if ( iSplit == iQuad ) {
8924 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8928 aBadRate += getBadRate( &quad, aCrit );
8931 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8933 nodes[ iSplit < iQuad ? i4 : i3 ]);
8934 aBadRate += getBadRate( &tria, aCrit );
8938 if ( aBadRate < aBestRate ) {
8940 aBestRate = aBadRate;
8945 // create new elements
8946 int aShapeId = FindShape( theFace );
8949 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8950 SMDS_MeshElement* newElem = 0;
8951 if ( iSplit == iBestQuad )
8952 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8957 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8959 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8960 myLastCreatedElems.Append(newElem);
8961 if ( aShapeId && newElem )
8962 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8965 // change nodes of theFace
8966 const SMDS_MeshNode* newNodes[ 4 ];
8967 newNodes[ 0 ] = linkNodes[ i1 ];
8968 newNodes[ 1 ] = linkNodes[ i2 ];
8969 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8970 newNodes[ 3 ] = nodes[ i4 ];
8971 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8972 const SMDS_MeshElement* newElem = 0;
8973 if (iSplit == iBestQuad)
8974 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8976 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8977 myLastCreatedElems.Append(newElem);
8978 if ( aShapeId && newElem )
8979 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8980 } // end if(!theFace->IsQuadratic())
8981 else { // theFace is quadratic
8982 // we have to split theFace on simple triangles and one simple quadrangle
8984 int nbshift = tmp*2;
8985 // shift nodes in nodes[] by nbshift
8987 for(i=0; i<nbshift; i++) {
8988 const SMDS_MeshNode* n = nodes[0];
8989 for(j=0; j<nbFaceNodes-1; j++) {
8990 nodes[j] = nodes[j+1];
8992 nodes[nbFaceNodes-1] = n;
8994 il1 = il1 - nbshift;
8995 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8996 // n0 n1 n2 n0 n1 n2
8997 // +-----+-----+ +-----+-----+
9006 // create new elements
9007 int aShapeId = FindShape( theFace );
9010 if(nbFaceNodes==6) { // quadratic triangle
9011 SMDS_MeshElement* newElem =
9012 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9013 myLastCreatedElems.Append(newElem);
9014 if ( aShapeId && newElem )
9015 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9016 if(theFace->IsMediumNode(nodes[il1])) {
9017 // create quadrangle
9018 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9019 myLastCreatedElems.Append(newElem);
9020 if ( aShapeId && newElem )
9021 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9027 // create quadrangle
9028 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9029 myLastCreatedElems.Append(newElem);
9030 if ( aShapeId && newElem )
9031 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9037 else { // nbFaceNodes==8 - quadratic quadrangle
9038 SMDS_MeshElement* newElem =
9039 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9040 myLastCreatedElems.Append(newElem);
9041 if ( aShapeId && newElem )
9042 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9043 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9044 myLastCreatedElems.Append(newElem);
9045 if ( aShapeId && newElem )
9046 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9047 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9048 myLastCreatedElems.Append(newElem);
9049 if ( aShapeId && newElem )
9050 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9051 if(theFace->IsMediumNode(nodes[il1])) {
9052 // create quadrangle
9053 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9054 myLastCreatedElems.Append(newElem);
9055 if ( aShapeId && newElem )
9056 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9062 // create quadrangle
9063 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9064 myLastCreatedElems.Append(newElem);
9065 if ( aShapeId && newElem )
9066 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9072 // create needed triangles using n1,n2,n3 and inserted nodes
9073 int nbn = 2 + aNodesToInsert.size();
9074 //const SMDS_MeshNode* aNodes[nbn];
9075 vector<const SMDS_MeshNode*> aNodes(nbn);
9076 aNodes[0] = nodes[n1];
9077 aNodes[nbn-1] = nodes[n2];
9078 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9079 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9080 aNodes[iNode++] = *nIt;
9082 for(i=1; i<nbn; i++) {
9083 SMDS_MeshElement* newElem =
9084 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9085 myLastCreatedElems.Append(newElem);
9086 if ( aShapeId && newElem )
9087 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9091 aMesh->RemoveElement(theFace);
9094 //=======================================================================
9095 //function : UpdateVolumes
9097 //=======================================================================
9098 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9099 const SMDS_MeshNode* theBetweenNode2,
9100 list<const SMDS_MeshNode*>& theNodesToInsert)
9102 myLastCreatedElems.Clear();
9103 myLastCreatedNodes.Clear();
9105 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9106 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9107 const SMDS_MeshElement* elem = invElemIt->next();
9109 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9110 SMDS_VolumeTool aVolume (elem);
9111 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9114 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9115 int iface, nbFaces = aVolume.NbFaces();
9116 vector<const SMDS_MeshNode *> poly_nodes;
9117 vector<int> quantities (nbFaces);
9119 for (iface = 0; iface < nbFaces; iface++) {
9120 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9121 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9122 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9124 for (int inode = 0; inode < nbFaceNodes; inode++) {
9125 poly_nodes.push_back(faceNodes[inode]);
9127 if (nbInserted == 0) {
9128 if (faceNodes[inode] == theBetweenNode1) {
9129 if (faceNodes[inode + 1] == theBetweenNode2) {
9130 nbInserted = theNodesToInsert.size();
9132 // add nodes to insert
9133 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9134 for (; nIt != theNodesToInsert.end(); nIt++) {
9135 poly_nodes.push_back(*nIt);
9139 else if (faceNodes[inode] == theBetweenNode2) {
9140 if (faceNodes[inode + 1] == theBetweenNode1) {
9141 nbInserted = theNodesToInsert.size();
9143 // add nodes to insert in reversed order
9144 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9146 for (; nIt != theNodesToInsert.begin(); nIt--) {
9147 poly_nodes.push_back(*nIt);
9149 poly_nodes.push_back(*nIt);
9156 quantities[iface] = nbFaceNodes + nbInserted;
9159 // Replace or update the volume
9160 SMESHDS_Mesh *aMesh = GetMeshDS();
9162 if (elem->IsPoly()) {
9163 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9167 int aShapeId = FindShape( elem );
9169 SMDS_MeshElement* newElem =
9170 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9171 myLastCreatedElems.Append(newElem);
9172 if (aShapeId && newElem)
9173 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9175 aMesh->RemoveElement(elem);
9180 //=======================================================================
9182 * \brief Convert elements contained in a submesh to quadratic
9183 * \retval int - nb of checked elements
9185 //=======================================================================
9187 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9188 SMESH_MesherHelper& theHelper,
9189 const bool theForce3d)
9192 if( !theSm ) return nbElem;
9194 vector<int> nbNodeInFaces;
9195 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9196 while(ElemItr->more())
9199 const SMDS_MeshElement* elem = ElemItr->next();
9200 if( !elem || elem->IsQuadratic() ) continue;
9202 int id = elem->GetID();
9203 //MESSAGE("elem " << id);
9204 id = 0; // get a free number for new elements
9205 int nbNodes = elem->NbNodes();
9206 SMDSAbs_ElementType aType = elem->GetType();
9208 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9209 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9210 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9212 const SMDS_MeshElement* NewElem = 0;
9218 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9226 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9229 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9232 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9237 case SMDSAbs_Volume :
9242 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9245 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9248 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9251 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9252 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9255 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9262 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9264 theSm->AddElement( NewElem );
9266 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9268 // if (!GetMeshDS()->isCompacted())
9269 // GetMeshDS()->compactMesh();
9273 //=======================================================================
9274 //function : ConvertToQuadratic
9276 //=======================================================================
9277 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9279 SMESHDS_Mesh* meshDS = GetMeshDS();
9281 SMESH_MesherHelper aHelper(*myMesh);
9282 aHelper.SetIsQuadratic( true );
9284 int nbCheckedElems = 0;
9285 if ( myMesh->HasShapeToMesh() )
9287 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9289 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9290 while ( smIt->more() ) {
9291 SMESH_subMesh* sm = smIt->next();
9292 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9293 aHelper.SetSubShape( sm->GetSubShape() );
9294 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9299 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9300 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9302 SMESHDS_SubMesh *smDS = 0;
9303 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9304 while(aEdgeItr->more())
9306 const SMDS_MeshEdge* edge = aEdgeItr->next();
9307 if(edge && !edge->IsQuadratic())
9309 int id = edge->GetID();
9310 //MESSAGE("edge->GetID() " << id);
9311 const SMDS_MeshNode* n1 = edge->GetNode(0);
9312 const SMDS_MeshNode* n2 = edge->GetNode(1);
9314 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9316 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9317 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9320 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9321 while(aFaceItr->more())
9323 const SMDS_MeshFace* face = aFaceItr->next();
9324 if(!face || face->IsQuadratic() ) continue;
9326 int id = face->GetID();
9327 int nbNodes = face->NbNodes();
9328 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9330 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9332 SMDS_MeshFace * NewFace = 0;
9336 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9339 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9342 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9344 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9346 vector<int> nbNodeInFaces;
9347 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9348 while(aVolumeItr->more())
9350 const SMDS_MeshVolume* volume = aVolumeItr->next();
9351 if(!volume || volume->IsQuadratic() ) continue;
9353 int id = volume->GetID();
9354 int nbNodes = volume->NbNodes();
9355 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9356 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9357 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9359 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9361 SMDS_MeshVolume * NewVolume = 0;
9365 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9366 nodes[3], id, theForce3d );
9369 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9370 nodes[3], nodes[4], id, theForce3d);
9373 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9374 nodes[3], nodes[4], nodes[5], id, theForce3d);
9377 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9378 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9381 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9383 ReplaceElemInGroups(volume, NewVolume, meshDS);
9387 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9388 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9389 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9390 aHelper.FixQuadraticElements();
9392 if (!GetMeshDS()->isCompacted())
9393 GetMeshDS()->compactMesh();
9396 //=======================================================================
9398 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9399 * \retval int - nb of checked elements
9401 //=======================================================================
9403 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9404 SMDS_ElemIteratorPtr theItr,
9405 const int theShapeID)
9408 SMESHDS_Mesh* meshDS = GetMeshDS();
9409 const bool notFromGroups = false;
9411 while( theItr->more() )
9413 const SMDS_MeshElement* elem = theItr->next();
9415 if( elem && elem->IsQuadratic())
9417 int id = elem->GetID();
9418 int nbNodes = elem->NbNodes();
9419 vector<const SMDS_MeshNode *> nodes, mediumNodes;
9420 nodes.reserve( nbNodes );
9421 mediumNodes.reserve( nbNodes );
9423 for(int i = 0; i < nbNodes; i++)
9425 const SMDS_MeshNode* n = elem->GetNode(i);
9427 if( elem->IsMediumNode( n ) )
9428 mediumNodes.push_back( n );
9430 nodes.push_back( n );
9432 if( nodes.empty() ) continue;
9433 SMDSAbs_ElementType aType = elem->GetType();
9435 //remove old quadratic element
9436 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9438 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9439 ReplaceElemInGroups(elem, NewElem, meshDS);
9440 if( theSm && NewElem )
9441 theSm->AddElement( NewElem );
9443 // remove medium nodes
9444 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9445 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9446 const SMDS_MeshNode* n = *nIt;
9447 if ( n->NbInverseElements() == 0 ) {
9448 if ( n->getshapeId() != theShapeID )
9449 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9450 ( n->getshapeId() ));
9452 meshDS->RemoveFreeNode( n, theSm );
9460 //=======================================================================
9461 //function : ConvertFromQuadratic
9463 //=======================================================================
9464 bool SMESH_MeshEditor::ConvertFromQuadratic()
9466 int nbCheckedElems = 0;
9467 if ( myMesh->HasShapeToMesh() )
9469 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9471 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9472 while ( smIt->more() ) {
9473 SMESH_subMesh* sm = smIt->next();
9474 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9475 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9481 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9482 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9484 SMESHDS_SubMesh *aSM = 0;
9485 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9491 //=======================================================================
9492 //function : SewSideElements
9494 //=======================================================================
9496 SMESH_MeshEditor::Sew_Error
9497 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9498 TIDSortedElemSet& theSide2,
9499 const SMDS_MeshNode* theFirstNode1,
9500 const SMDS_MeshNode* theFirstNode2,
9501 const SMDS_MeshNode* theSecondNode1,
9502 const SMDS_MeshNode* theSecondNode2)
9504 myLastCreatedElems.Clear();
9505 myLastCreatedNodes.Clear();
9507 MESSAGE ("::::SewSideElements()");
9508 if ( theSide1.size() != theSide2.size() )
9509 return SEW_DIFF_NB_OF_ELEMENTS;
9511 Sew_Error aResult = SEW_OK;
9513 // 1. Build set of faces representing each side
9514 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9515 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9517 // =======================================================================
9518 // 1. Build set of faces representing each side:
9519 // =======================================================================
9520 // a. build set of nodes belonging to faces
9521 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9522 // c. create temporary faces representing side of volumes if correspondent
9523 // face does not exist
9525 SMESHDS_Mesh* aMesh = GetMeshDS();
9526 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9527 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9528 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9529 set<const SMDS_MeshElement*> volSet1, volSet2;
9530 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9531 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9532 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9533 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9534 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9535 int iSide, iFace, iNode;
9537 list<const SMDS_MeshElement* > tempFaceList;
9538 for ( iSide = 0; iSide < 2; iSide++ ) {
9539 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9540 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9541 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9542 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9543 set<const SMDS_MeshElement*>::iterator vIt;
9544 TIDSortedElemSet::iterator eIt;
9545 set<const SMDS_MeshNode*>::iterator nIt;
9547 // check that given nodes belong to given elements
9548 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9549 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9550 int firstIndex = -1, secondIndex = -1;
9551 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9552 const SMDS_MeshElement* elem = *eIt;
9553 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9554 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9555 if ( firstIndex > -1 && secondIndex > -1 ) break;
9557 if ( firstIndex < 0 || secondIndex < 0 ) {
9558 // we can simply return until temporary faces created
9559 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9562 // -----------------------------------------------------------
9563 // 1a. Collect nodes of existing faces
9564 // and build set of face nodes in order to detect missing
9565 // faces corresponding to sides of volumes
9566 // -----------------------------------------------------------
9568 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9570 // loop on the given element of a side
9571 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9572 //const SMDS_MeshElement* elem = *eIt;
9573 const SMDS_MeshElement* elem = *eIt;
9574 if ( elem->GetType() == SMDSAbs_Face ) {
9575 faceSet->insert( elem );
9576 set <const SMDS_MeshNode*> faceNodeSet;
9577 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9578 while ( nodeIt->more() ) {
9579 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9580 nodeSet->insert( n );
9581 faceNodeSet.insert( n );
9583 setOfFaceNodeSet.insert( faceNodeSet );
9585 else if ( elem->GetType() == SMDSAbs_Volume )
9586 volSet->insert( elem );
9588 // ------------------------------------------------------------------------------
9589 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9590 // ------------------------------------------------------------------------------
9592 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9593 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9594 while ( fIt->more() ) { // loop on faces sharing a node
9595 const SMDS_MeshElement* f = fIt->next();
9596 if ( faceSet->find( f ) == faceSet->end() ) {
9597 // check if all nodes are in nodeSet and
9598 // complete setOfFaceNodeSet if they are
9599 set <const SMDS_MeshNode*> faceNodeSet;
9600 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9601 bool allInSet = true;
9602 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9603 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9604 if ( nodeSet->find( n ) == nodeSet->end() )
9607 faceNodeSet.insert( n );
9610 faceSet->insert( f );
9611 setOfFaceNodeSet.insert( faceNodeSet );
9617 // -------------------------------------------------------------------------
9618 // 1c. Create temporary faces representing sides of volumes if correspondent
9619 // face does not exist
9620 // -------------------------------------------------------------------------
9622 if ( !volSet->empty() ) {
9623 //int nodeSetSize = nodeSet->size();
9625 // loop on given volumes
9626 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9627 SMDS_VolumeTool vol (*vIt);
9628 // loop on volume faces: find free faces
9629 // --------------------------------------
9630 list<const SMDS_MeshElement* > freeFaceList;
9631 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9632 if ( !vol.IsFreeFace( iFace ))
9634 // check if there is already a face with same nodes in a face set
9635 const SMDS_MeshElement* aFreeFace = 0;
9636 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9637 int nbNodes = vol.NbFaceNodes( iFace );
9638 set <const SMDS_MeshNode*> faceNodeSet;
9639 vol.GetFaceNodes( iFace, faceNodeSet );
9640 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9642 // no such a face is given but it still can exist, check it
9643 if ( nbNodes == 3 ) {
9644 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9646 else if ( nbNodes == 4 ) {
9647 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9650 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9651 aFreeFace = aMesh->FindFace(poly_nodes);
9655 // create a temporary face
9656 if ( nbNodes == 3 ) {
9657 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9658 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9660 else if ( nbNodes == 4 ) {
9661 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9662 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9665 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9666 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9667 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9671 freeFaceList.push_back( aFreeFace );
9672 tempFaceList.push_back( aFreeFace );
9675 } // loop on faces of a volume
9677 // choose one of several free faces
9678 // --------------------------------------
9679 if ( freeFaceList.size() > 1 ) {
9680 // choose a face having max nb of nodes shared by other elems of a side
9681 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9682 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9683 while ( fIt != freeFaceList.end() ) { // loop on free faces
9684 int nbSharedNodes = 0;
9685 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9686 while ( nodeIt->more() ) { // loop on free face nodes
9687 const SMDS_MeshNode* n =
9688 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9689 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9690 while ( invElemIt->more() ) {
9691 const SMDS_MeshElement* e = invElemIt->next();
9692 if ( faceSet->find( e ) != faceSet->end() )
9694 if ( elemSet->find( e ) != elemSet->end() )
9698 if ( nbSharedNodes >= maxNbNodes ) {
9699 maxNbNodes = nbSharedNodes;
9703 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9705 if ( freeFaceList.size() > 1 )
9707 // could not choose one face, use another way
9708 // choose a face most close to the bary center of the opposite side
9709 gp_XYZ aBC( 0., 0., 0. );
9710 set <const SMDS_MeshNode*> addedNodes;
9711 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9712 eIt = elemSet2->begin();
9713 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9714 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9715 while ( nodeIt->more() ) { // loop on free face nodes
9716 const SMDS_MeshNode* n =
9717 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9718 if ( addedNodes.insert( n ).second )
9719 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9722 aBC /= addedNodes.size();
9723 double minDist = DBL_MAX;
9724 fIt = freeFaceList.begin();
9725 while ( fIt != freeFaceList.end() ) { // loop on free faces
9727 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9728 while ( nodeIt->more() ) { // loop on free face nodes
9729 const SMDS_MeshNode* n =
9730 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9731 gp_XYZ p( n->X(),n->Y(),n->Z() );
9732 dist += ( aBC - p ).SquareModulus();
9734 if ( dist < minDist ) {
9736 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9739 fIt = freeFaceList.erase( fIt++ );
9742 } // choose one of several free faces of a volume
9744 if ( freeFaceList.size() == 1 ) {
9745 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9746 faceSet->insert( aFreeFace );
9747 // complete a node set with nodes of a found free face
9748 // for ( iNode = 0; iNode < ; iNode++ )
9749 // nodeSet->insert( fNodes[ iNode ] );
9752 } // loop on volumes of a side
9754 // // complete a set of faces if new nodes in a nodeSet appeared
9755 // // ----------------------------------------------------------
9756 // if ( nodeSetSize != nodeSet->size() ) {
9757 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9758 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9759 // while ( fIt->more() ) { // loop on faces sharing a node
9760 // const SMDS_MeshElement* f = fIt->next();
9761 // if ( faceSet->find( f ) == faceSet->end() ) {
9762 // // check if all nodes are in nodeSet and
9763 // // complete setOfFaceNodeSet if they are
9764 // set <const SMDS_MeshNode*> faceNodeSet;
9765 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9766 // bool allInSet = true;
9767 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9768 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9769 // if ( nodeSet->find( n ) == nodeSet->end() )
9770 // allInSet = false;
9772 // faceNodeSet.insert( n );
9774 // if ( allInSet ) {
9775 // faceSet->insert( f );
9776 // setOfFaceNodeSet.insert( faceNodeSet );
9782 } // Create temporary faces, if there are volumes given
9785 if ( faceSet1.size() != faceSet2.size() ) {
9786 // delete temporary faces: they are in reverseElements of actual nodes
9787 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9788 // while ( tmpFaceIt->more() )
9789 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9790 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9791 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9792 // aMesh->RemoveElement(*tmpFaceIt);
9793 MESSAGE("Diff nb of faces");
9794 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9797 // ============================================================
9798 // 2. Find nodes to merge:
9799 // bind a node to remove to a node to put instead
9800 // ============================================================
9802 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9803 if ( theFirstNode1 != theFirstNode2 )
9804 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9805 if ( theSecondNode1 != theSecondNode2 )
9806 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9808 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9809 set< long > linkIdSet; // links to process
9810 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9812 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9813 list< NLink > linkList[2];
9814 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9815 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9816 // loop on links in linkList; find faces by links and append links
9817 // of the found faces to linkList
9818 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9819 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9820 NLink link[] = { *linkIt[0], *linkIt[1] };
9821 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9822 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9825 // by links, find faces in the face sets,
9826 // and find indices of link nodes in the found faces;
9827 // in a face set, there is only one or no face sharing a link
9828 // ---------------------------------------------------------------
9830 const SMDS_MeshElement* face[] = { 0, 0 };
9831 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9832 vector<const SMDS_MeshNode*> fnodes1(9);
9833 vector<const SMDS_MeshNode*> fnodes2(9);
9834 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9835 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9836 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9837 int iLinkNode[2][2];
9838 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9839 const SMDS_MeshNode* n1 = link[iSide].first;
9840 const SMDS_MeshNode* n2 = link[iSide].second;
9841 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9842 set< const SMDS_MeshElement* > fMap;
9843 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9844 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9845 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9846 while ( fIt->more() ) { // loop on faces sharing a node
9847 const SMDS_MeshElement* f = fIt->next();
9848 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9849 ! fMap.insert( f ).second ) // f encounters twice
9851 if ( face[ iSide ] ) {
9852 MESSAGE( "2 faces per link " );
9853 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9857 faceSet->erase( f );
9858 // get face nodes and find ones of a link
9863 fnodes1.resize(f->NbNodes()+1);
9864 notLinkNodes1.resize(f->NbNodes()-2);
9867 fnodes2.resize(f->NbNodes()+1);
9868 notLinkNodes2.resize(f->NbNodes()-2);
9871 if(!f->IsQuadratic()) {
9872 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9873 while ( nIt->more() ) {
9874 const SMDS_MeshNode* n =
9875 static_cast<const SMDS_MeshNode*>( nIt->next() );
9877 iLinkNode[ iSide ][ 0 ] = iNode;
9879 else if ( n == n2 ) {
9880 iLinkNode[ iSide ][ 1 ] = iNode;
9882 //else if ( notLinkNodes[ iSide ][ 0 ] )
9883 // notLinkNodes[ iSide ][ 1 ] = n;
9885 // notLinkNodes[ iSide ][ 0 ] = n;
9889 notLinkNodes1[nbl] = n;
9890 //notLinkNodes1.push_back(n);
9892 notLinkNodes2[nbl] = n;
9893 //notLinkNodes2.push_back(n);
9895 //faceNodes[ iSide ][ iNode++ ] = n;
9897 fnodes1[iNode++] = n;
9900 fnodes2[iNode++] = n;
9904 else { // f->IsQuadratic()
9905 const SMDS_VtkFace* F =
9906 dynamic_cast<const SMDS_VtkFace*>(f);
9907 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9908 // use special nodes iterator
9909 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9910 while ( anIter->more() ) {
9911 const SMDS_MeshNode* n =
9912 static_cast<const SMDS_MeshNode*>( anIter->next() );
9914 iLinkNode[ iSide ][ 0 ] = iNode;
9916 else if ( n == n2 ) {
9917 iLinkNode[ iSide ][ 1 ] = iNode;
9922 notLinkNodes1[nbl] = n;
9925 notLinkNodes2[nbl] = n;
9929 fnodes1[iNode++] = n;
9932 fnodes2[iNode++] = n;
9936 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9938 fnodes1[iNode] = fnodes1[0];
9941 fnodes2[iNode] = fnodes1[0];
9948 // check similarity of elements of the sides
9949 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9950 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9951 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9952 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9955 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9957 break; // do not return because it s necessary to remove tmp faces
9960 // set nodes to merge
9961 // -------------------
9963 if ( face[0] && face[1] ) {
9964 int nbNodes = face[0]->NbNodes();
9965 if ( nbNodes != face[1]->NbNodes() ) {
9966 MESSAGE("Diff nb of face nodes");
9967 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9968 break; // do not return because it s necessary to remove tmp faces
9970 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9971 if ( nbNodes == 3 ) {
9972 //nReplaceMap.insert( TNodeNodeMap::value_type
9973 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9974 nReplaceMap.insert( TNodeNodeMap::value_type
9975 ( notLinkNodes1[0], notLinkNodes2[0] ));
9978 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9979 // analyse link orientation in faces
9980 int i1 = iLinkNode[ iSide ][ 0 ];
9981 int i2 = iLinkNode[ iSide ][ 1 ];
9982 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9983 // if notLinkNodes are the first and the last ones, then
9984 // their order does not correspond to the link orientation
9985 if (( i1 == 1 && i2 == 2 ) ||
9986 ( i1 == 2 && i2 == 1 ))
9987 reverse[ iSide ] = !reverse[ iSide ];
9989 if ( reverse[0] == reverse[1] ) {
9990 //nReplaceMap.insert( TNodeNodeMap::value_type
9991 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9992 //nReplaceMap.insert( TNodeNodeMap::value_type
9993 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9994 for(int nn=0; nn<nbNodes-2; nn++) {
9995 nReplaceMap.insert( TNodeNodeMap::value_type
9996 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10000 //nReplaceMap.insert( TNodeNodeMap::value_type
10001 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10002 //nReplaceMap.insert( TNodeNodeMap::value_type
10003 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10004 for(int nn=0; nn<nbNodes-2; nn++) {
10005 nReplaceMap.insert( TNodeNodeMap::value_type
10006 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10011 // add other links of the faces to linkList
10012 // -----------------------------------------
10014 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10015 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10016 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10017 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10018 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10019 if ( !iter_isnew.second ) { // already in a set: no need to process
10020 linkIdSet.erase( iter_isnew.first );
10022 else // new in set == encountered for the first time: add
10024 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10025 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10026 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10027 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10028 linkList[0].push_back ( NLink( n1, n2 ));
10029 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10033 } // loop on link lists
10035 if ( aResult == SEW_OK &&
10036 ( linkIt[0] != linkList[0].end() ||
10037 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10038 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10039 " " << (faceSetPtr[1]->empty()));
10040 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10043 // ====================================================================
10044 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10045 // ====================================================================
10047 // delete temporary faces: they are in reverseElements of actual nodes
10048 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10049 // while ( tmpFaceIt->more() )
10050 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10051 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10052 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10053 // aMesh->RemoveElement(*tmpFaceIt);
10055 if ( aResult != SEW_OK)
10058 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10059 // loop on nodes replacement map
10060 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10061 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10062 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10063 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10064 nodeIDsToRemove.push_back( nToRemove->GetID() );
10065 // loop on elements sharing nToRemove
10066 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10067 while ( invElemIt->more() ) {
10068 const SMDS_MeshElement* e = invElemIt->next();
10069 // get a new suite of nodes: make replacement
10070 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10071 vector< const SMDS_MeshNode*> nodes( nbNodes );
10072 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10073 while ( nIt->more() ) {
10074 const SMDS_MeshNode* n =
10075 static_cast<const SMDS_MeshNode*>( nIt->next() );
10076 nnIt = nReplaceMap.find( n );
10077 if ( nnIt != nReplaceMap.end() ) {
10079 n = (*nnIt).second;
10083 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10084 // elemIDsToRemove.push_back( e->GetID() );
10088 SMDSAbs_ElementType etyp = e->GetType();
10089 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10092 myLastCreatedElems.Append(newElem);
10093 AddToSameGroups(newElem, e, aMesh);
10094 int aShapeId = e->getshapeId();
10097 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10100 aMesh->RemoveElement(e);
10105 Remove( nodeIDsToRemove, true );
10110 //================================================================================
10112 * \brief Find corresponding nodes in two sets of faces
10113 * \param theSide1 - first face set
10114 * \param theSide2 - second first face
10115 * \param theFirstNode1 - a boundary node of set 1
10116 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10117 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10118 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10119 * \param nReplaceMap - output map of corresponding nodes
10120 * \retval bool - is a success or not
10122 //================================================================================
10125 //#define DEBUG_MATCHING_NODES
10128 SMESH_MeshEditor::Sew_Error
10129 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10130 set<const SMDS_MeshElement*>& theSide2,
10131 const SMDS_MeshNode* theFirstNode1,
10132 const SMDS_MeshNode* theFirstNode2,
10133 const SMDS_MeshNode* theSecondNode1,
10134 const SMDS_MeshNode* theSecondNode2,
10135 TNodeNodeMap & nReplaceMap)
10137 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10139 nReplaceMap.clear();
10140 if ( theFirstNode1 != theFirstNode2 )
10141 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10142 if ( theSecondNode1 != theSecondNode2 )
10143 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10145 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10146 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10148 list< NLink > linkList[2];
10149 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10150 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10152 // loop on links in linkList; find faces by links and append links
10153 // of the found faces to linkList
10154 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10155 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10156 NLink link[] = { *linkIt[0], *linkIt[1] };
10157 if ( linkSet.find( link[0] ) == linkSet.end() )
10160 // by links, find faces in the face sets,
10161 // and find indices of link nodes in the found faces;
10162 // in a face set, there is only one or no face sharing a link
10163 // ---------------------------------------------------------------
10165 const SMDS_MeshElement* face[] = { 0, 0 };
10166 list<const SMDS_MeshNode*> notLinkNodes[2];
10167 //bool reverse[] = { false, false }; // order of notLinkNodes
10169 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10171 const SMDS_MeshNode* n1 = link[iSide].first;
10172 const SMDS_MeshNode* n2 = link[iSide].second;
10173 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10174 set< const SMDS_MeshElement* > facesOfNode1;
10175 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10177 // during a loop of the first node, we find all faces around n1,
10178 // during a loop of the second node, we find one face sharing both n1 and n2
10179 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10180 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10181 while ( fIt->more() ) { // loop on faces sharing a node
10182 const SMDS_MeshElement* f = fIt->next();
10183 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10184 ! facesOfNode1.insert( f ).second ) // f encounters twice
10186 if ( face[ iSide ] ) {
10187 MESSAGE( "2 faces per link " );
10188 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10191 faceSet->erase( f );
10193 // get not link nodes
10194 int nbN = f->NbNodes();
10195 if ( f->IsQuadratic() )
10197 nbNodes[ iSide ] = nbN;
10198 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10199 int i1 = f->GetNodeIndex( n1 );
10200 int i2 = f->GetNodeIndex( n2 );
10201 int iEnd = nbN, iBeg = -1, iDelta = 1;
10202 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10204 std::swap( iEnd, iBeg ); iDelta = -1;
10209 if ( i == iEnd ) i = iBeg + iDelta;
10210 if ( i == i1 ) break;
10211 nodes.push_back ( f->GetNode( i ) );
10217 // check similarity of elements of the sides
10218 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10219 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10220 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10221 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10224 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10228 // set nodes to merge
10229 // -------------------
10231 if ( face[0] && face[1] ) {
10232 if ( nbNodes[0] != nbNodes[1] ) {
10233 MESSAGE("Diff nb of face nodes");
10234 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10236 #ifdef DEBUG_MATCHING_NODES
10237 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10238 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10239 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10241 int nbN = nbNodes[0];
10243 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10244 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10245 for ( int i = 0 ; i < nbN - 2; ++i ) {
10246 #ifdef DEBUG_MATCHING_NODES
10247 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10249 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10253 // add other links of the face 1 to linkList
10254 // -----------------------------------------
10256 const SMDS_MeshElement* f0 = face[0];
10257 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10258 for ( int i = 0; i < nbN; i++ )
10260 const SMDS_MeshNode* n2 = f0->GetNode( i );
10261 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10262 linkSet.insert( SMESH_TLink( n1, n2 ));
10263 if ( !iter_isnew.second ) { // already in a set: no need to process
10264 linkSet.erase( iter_isnew.first );
10266 else // new in set == encountered for the first time: add
10268 #ifdef DEBUG_MATCHING_NODES
10269 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10270 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10272 linkList[0].push_back ( NLink( n1, n2 ));
10273 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10278 } // loop on link lists
10283 //================================================================================
10285 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10286 \param theElems - the list of elements (edges or faces) to be replicated
10287 The nodes for duplication could be found from these elements
10288 \param theNodesNot - list of nodes to NOT replicate
10289 \param theAffectedElems - the list of elements (cells and edges) to which the
10290 replicated nodes should be associated to.
10291 \return TRUE if operation has been completed successfully, FALSE otherwise
10293 //================================================================================
10295 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10296 const TIDSortedElemSet& theNodesNot,
10297 const TIDSortedElemSet& theAffectedElems )
10299 myLastCreatedElems.Clear();
10300 myLastCreatedNodes.Clear();
10302 if ( theElems.size() == 0 )
10305 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10310 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10311 // duplicate elements and nodes
10312 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10313 // replce nodes by duplications
10314 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10318 //================================================================================
10320 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10321 \param theMeshDS - mesh instance
10322 \param theElems - the elements replicated or modified (nodes should be changed)
10323 \param theNodesNot - nodes to NOT replicate
10324 \param theNodeNodeMap - relation of old node to new created node
10325 \param theIsDoubleElem - flag os to replicate element or modify
10326 \return TRUE if operation has been completed successfully, FALSE otherwise
10328 //================================================================================
10330 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10331 const TIDSortedElemSet& theElems,
10332 const TIDSortedElemSet& theNodesNot,
10333 std::map< const SMDS_MeshNode*,
10334 const SMDS_MeshNode* >& theNodeNodeMap,
10335 const bool theIsDoubleElem )
10337 MESSAGE("doubleNodes");
10338 // iterate on through element and duplicate them (by nodes duplication)
10340 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10341 for ( ; elemItr != theElems.end(); ++elemItr )
10343 const SMDS_MeshElement* anElem = *elemItr;
10347 bool isDuplicate = false;
10348 // duplicate nodes to duplicate element
10349 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10350 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10352 while ( anIter->more() )
10355 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10356 SMDS_MeshNode* aNewNode = aCurrNode;
10357 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10358 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10359 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10362 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10363 theNodeNodeMap[ aCurrNode ] = aNewNode;
10364 myLastCreatedNodes.Append( aNewNode );
10366 isDuplicate |= (aCurrNode != aNewNode);
10367 newNodes[ ind++ ] = aNewNode;
10369 if ( !isDuplicate )
10372 if ( theIsDoubleElem )
10373 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10376 MESSAGE("ChangeElementNodes");
10377 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10384 //================================================================================
10386 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10387 \param theNodes - identifiers of nodes to be doubled
10388 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10389 nodes. If list of element identifiers is empty then nodes are doubled but
10390 they not assigned to elements
10391 \return TRUE if operation has been completed successfully, FALSE otherwise
10393 //================================================================================
10395 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10396 const std::list< int >& theListOfModifiedElems )
10398 MESSAGE("DoubleNodes");
10399 myLastCreatedElems.Clear();
10400 myLastCreatedNodes.Clear();
10402 if ( theListOfNodes.size() == 0 )
10405 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10409 // iterate through nodes and duplicate them
10411 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10413 std::list< int >::const_iterator aNodeIter;
10414 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10416 int aCurr = *aNodeIter;
10417 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10423 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10426 anOldNodeToNewNode[ aNode ] = aNewNode;
10427 myLastCreatedNodes.Append( aNewNode );
10431 // Create map of new nodes for modified elements
10433 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10435 std::list< int >::const_iterator anElemIter;
10436 for ( anElemIter = theListOfModifiedElems.begin();
10437 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10439 int aCurr = *anElemIter;
10440 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10444 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10446 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10448 while ( anIter->more() )
10450 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10451 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10453 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10454 aNodeArr[ ind++ ] = aNewNode;
10457 aNodeArr[ ind++ ] = aCurrNode;
10459 anElemToNodes[ anElem ] = aNodeArr;
10462 // Change nodes of elements
10464 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10465 anElemToNodesIter = anElemToNodes.begin();
10466 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10468 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10469 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10472 MESSAGE("ChangeElementNodes");
10473 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10482 //================================================================================
10484 \brief Check if element located inside shape
10485 \return TRUE if IN or ON shape, FALSE otherwise
10487 //================================================================================
10489 template<class Classifier>
10490 bool isInside(const SMDS_MeshElement* theElem,
10491 Classifier& theClassifier,
10492 const double theTol)
10494 gp_XYZ centerXYZ (0, 0, 0);
10495 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10496 while (aNodeItr->more())
10497 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10499 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10500 theClassifier.Perform(aPnt, theTol);
10501 TopAbs_State aState = theClassifier.State();
10502 return (aState == TopAbs_IN || aState == TopAbs_ON );
10505 //================================================================================
10507 * \brief Classifier of the 3D point on the TopoDS_Face
10508 * with interaface suitable for isInside()
10510 //================================================================================
10512 struct _FaceClassifier
10514 Extrema_ExtPS _extremum;
10515 BRepAdaptor_Surface _surface;
10516 TopAbs_State _state;
10518 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10520 _extremum.Initialize( _surface,
10521 _surface.FirstUParameter(), _surface.LastUParameter(),
10522 _surface.FirstVParameter(), _surface.LastVParameter(),
10523 _surface.Tolerance(), _surface.Tolerance() );
10525 void Perform(const gp_Pnt& aPnt, double theTol)
10527 _state = TopAbs_OUT;
10528 _extremum.Perform(aPnt);
10529 if ( _extremum.IsDone() )
10530 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10531 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10533 TopAbs_State State() const
10540 //================================================================================
10542 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10543 \param theElems - group of of elements (edges or faces) to be replicated
10544 \param theNodesNot - group of nodes not to replicate
10545 \param theShape - shape to detect affected elements (element which geometric center
10546 located on or inside shape).
10547 The replicated nodes should be associated to affected elements.
10548 \return TRUE if operation has been completed successfully, FALSE otherwise
10550 //================================================================================
10552 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10553 const TIDSortedElemSet& theNodesNot,
10554 const TopoDS_Shape& theShape )
10556 if ( theShape.IsNull() )
10559 const double aTol = Precision::Confusion();
10560 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10561 auto_ptr<_FaceClassifier> aFaceClassifier;
10562 if ( theShape.ShapeType() == TopAbs_SOLID )
10564 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10565 bsc3d->PerformInfinitePoint(aTol);
10567 else if (theShape.ShapeType() == TopAbs_FACE )
10569 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10572 // iterates on indicated elements and get elements by back references from their nodes
10573 TIDSortedElemSet anAffected;
10574 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10575 for ( ; elemItr != theElems.end(); ++elemItr )
10577 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10581 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10582 while ( nodeItr->more() )
10584 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10585 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10587 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10588 while ( backElemItr->more() )
10590 const SMDS_MeshElement* curElem = backElemItr->next();
10591 if ( curElem && theElems.find(curElem) == theElems.end() &&
10593 isInside( curElem, *bsc3d, aTol ) :
10594 isInside( curElem, *aFaceClassifier, aTol )))
10595 anAffected.insert( curElem );
10599 return DoubleNodes( theElems, theNodesNot, anAffected );
10603 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10604 * The list of groups must describe a partition of the mesh volumes.
10605 * The nodes of the internal faces at the boundaries of the groups are doubled.
10606 * In option, the internal faces are replaced by flat elements.
10607 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10608 * @param theElems - list of groups of volumes, where a group of volume is a set of
10609 * SMDS_MeshElements sorted by Id.
10610 * @param createJointElems - if TRUE, create the elements
10611 * @return TRUE if operation has been completed successfully, FALSE otherwise
10613 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10614 bool createJointElems)
10616 MESSAGE("------------------------------------------------------");
10617 MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10618 MESSAGE("------------------------------------------------------");
10620 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10621 meshDS->BuildDownWardConnectivity(false);
10623 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10625 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10626 // build the list of nodes shared by 2 or more domains, with their domain indexes
10628 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10629 std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
10630 faceDomains.clear();
10631 nodeDomains.clear();
10632 std::map<int,int> emptyMap;
10635 for (int idom = 0; idom < theElems.size(); idom++)
10638 // --- build a map (face to duplicate --> volume to modify)
10639 // with all the faces shared by 2 domains (group of elements)
10640 // and corresponding volume of this domain, for each shared face.
10641 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10643 const TIDSortedElemSet& domain = theElems[idom];
10644 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10645 for (; elemItr != domain.end(); ++elemItr)
10647 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10650 int vtkId = anElem->getVtkId();
10651 int neighborsVtkIds[NBMAXNEIGHBORS];
10652 int downIds[NBMAXNEIGHBORS];
10653 unsigned char downTypes[NBMAXNEIGHBORS];
10654 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10655 for (int n = 0; n < nbNeighbors; n++)
10657 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10658 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10659 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10661 DownIdType face(downIds[n], downTypes[n]);
10662 if (!faceDomains.count(face))
10663 faceDomains[face] = emptyMap; // create an empty entry for face
10664 if (!faceDomains[face].count(idom))
10666 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10673 MESSAGE("Number of shared faces " << faceDomains.size());
10675 // --- for each shared face, get the nodes
10676 // for each node, for each domain of the face, create a clone of the node
10678 std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10679 for( ; itface != faceDomains.end();++itface )
10681 DownIdType face = itface->first;
10682 std::map<int,int> domvol = itface->second;
10683 std::set<int> oldNodes;
10685 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10686 std::set<int>::iterator itn = oldNodes.begin();
10687 for (;itn != oldNodes.end(); ++itn)
10690 if (!nodeDomains.count(oldId))
10691 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10692 std::map<int,int>::iterator itdom = domvol.begin();
10693 for(; itdom != domvol.end(); ++itdom)
10695 int idom = itdom->first;
10696 if ( nodeDomains[oldId].empty() )
10697 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10700 double *coords = grid->GetPoint(oldId);
10701 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10702 int newId = newNode->getVtkId();
10703 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10709 // --- iterate on shared faces (volumes to modify, face to extrude)
10710 // get node id's of the face (id SMDS = id VTK)
10711 // create flat element with old and new nodes if requested
10713 if (createJointElems)
10715 itface = faceDomains.begin();
10716 for( ; itface != faceDomains.end();++itface )
10718 DownIdType face = itface->first;
10719 std::set<int> oldNodes;
10720 std::set<int>::iterator itn;
10722 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10723 std::map<int,int> localClonedNodeIds;
10725 std::map<int,int> domvol = itface->second;
10726 std::map<int,int>::iterator itdom = domvol.begin();
10727 int dom1 = itdom->first;
10728 int vtkVolId = itdom->second;
10730 int dom2 = itdom->first;
10732 localClonedNodeIds.clear();
10733 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10737 if (nodeDomains[oldId].count(dom1))
10738 refid = nodeDomains[oldId][dom1];
10740 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10742 if (nodeDomains[oldId].count(dom2))
10743 newid = nodeDomains[oldId][dom2];
10745 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10746 localClonedNodeIds[oldId] = newid;
10748 meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10752 // --- iterate on shared faces (volumes to modify, face to extrude)
10753 // get node id's of the face
10754 // replace old nodes by new nodes in volumes, and update inverse connectivity
10756 itface = faceDomains.begin();
10757 for( ; itface != faceDomains.end();++itface )
10759 DownIdType face = itface->first;
10760 std::set<int> oldNodes;
10761 std::set<int>::iterator itn;
10763 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10764 std::map<int,int> localClonedNodeIds;
10766 std::map<int,int> domvol = itface->second;
10767 std::map<int,int>::iterator itdom = domvol.begin();
10768 for(; itdom != domvol.end(); ++itdom)
10770 int idom = itdom->first;
10771 int vtkVolId = itdom->second;
10772 localClonedNodeIds.clear();
10773 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10776 if (nodeDomains[oldId].count(idom))
10777 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10779 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10782 grid->BuildLinks();
10784 // TODO replace also old nodes by new nodes in faces and edges
10790 //================================================================================
10792 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10793 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10794 * \return TRUE if operation has been completed successfully, FALSE otherwise
10796 //================================================================================
10798 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10800 // iterates on volume elements and detect all free faces on them
10801 SMESHDS_Mesh* aMesh = GetMeshDS();
10804 //bool res = false;
10805 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10806 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10809 const SMDS_MeshVolume* volume = vIt->next();
10810 SMDS_VolumeTool vTool( volume );
10811 vTool.SetExternalNormal();
10812 const bool isPoly = volume->IsPoly();
10813 const bool isQuad = volume->IsQuadratic();
10814 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10816 if (!vTool.IsFreeFace(iface))
10819 vector<const SMDS_MeshNode *> nodes;
10820 int nbFaceNodes = vTool.NbFaceNodes(iface);
10821 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10823 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10824 nodes.push_back(faceNodes[inode]);
10826 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10827 nodes.push_back(faceNodes[inode]);
10829 // add new face based on volume nodes
10830 if (aMesh->FindFace( nodes ) ) {
10832 continue; // face already exsist
10834 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10838 return ( nbFree==(nbExisted+nbCreated) );
10843 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10845 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10847 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10850 //================================================================================
10852 * \brief Creates missing boundary elements
10853 * \param elements - elements whose boundary is to be checked
10854 * \param dimension - defines type of boundary elements to create
10855 * \param group - a group to store created boundary elements in
10856 * \param targetMesh - a mesh to store created boundary elements in
10857 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10858 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10859 * boundary elements will be copied into the targetMesh
10861 //================================================================================
10863 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10864 Bnd_Dimension dimension,
10865 SMESH_Group* group/*=0*/,
10866 SMESH_Mesh* targetMesh/*=0*/,
10867 bool toCopyElements/*=false*/,
10868 bool toCopyExistingBondary/*=false*/)
10870 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10871 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10872 // hope that all elements are of the same type, do not check them all
10873 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10874 throw SALOME_Exception(LOCALIZED("wrong element type"));
10877 toCopyElements = toCopyExistingBondary = false;
10879 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10880 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10882 SMDS_VolumeTool vTool;
10883 TIDSortedElemSet emptySet, avoidSet;
10886 typedef vector<const SMDS_MeshNode*> TConnectivity;
10888 SMDS_ElemIteratorPtr eIt;
10889 if (elements.empty())
10890 eIt = aMesh->elementsIterator(elemType);
10892 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10894 while (eIt->more())
10896 const SMDS_MeshElement* elem = eIt->next();
10897 const int iQuad = elem->IsQuadratic();
10899 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10900 vector<const SMDS_MeshElement*> presentBndElems;
10901 vector<TConnectivity> missingBndElems;
10902 TConnectivity nodes;
10903 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10905 vTool.SetExternalNormal();
10906 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10908 if (!vTool.IsFreeFace(iface))
10910 int nbFaceNodes = vTool.NbFaceNodes(iface);
10911 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10912 if ( missType == SMDSAbs_Edge ) // boundary edges
10914 nodes.resize( 2+iQuad );
10915 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10917 for ( int j = 0; j < nodes.size(); ++j )
10919 if ( const SMDS_MeshElement* edge =
10920 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10921 presentBndElems.push_back( edge );
10923 missingBndElems.push_back( nodes );
10926 else // boundary face
10929 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10930 nodes.push_back( nn[inode] );
10932 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10933 nodes.push_back( nn[inode] );
10935 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10936 presentBndElems.push_back( f );
10938 missingBndElems.push_back( nodes );
10942 else // elem is a face ------------------------------------------
10944 avoidSet.clear(), avoidSet.insert( elem );
10945 int nbNodes = elem->NbCornerNodes();
10946 nodes.resize( 2 /*+ iQuad*/);
10947 for ( int i = 0; i < nbNodes; i++ )
10949 nodes[0] = elem->GetNode(i);
10950 nodes[1] = elem->GetNode((i+1)%nbNodes);
10951 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10952 continue; // not free link
10955 //nodes[2] = elem->GetNode( i + nbNodes );
10956 if ( const SMDS_MeshElement* edge =
10957 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10958 presentBndElems.push_back( edge );
10960 missingBndElems.push_back( nodes );
10964 // 2. Add missing boundary elements
10965 if ( targetMesh != myMesh )
10966 // instead of making a map of nodes in this mesh and targetMesh,
10967 // we create nodes with same IDs. We can renumber them later, if needed
10968 for ( int i = 0; i < missingBndElems.size(); ++i )
10970 TConnectivity& srcNodes = missingBndElems[i];
10971 TConnectivity nodes( srcNodes.size() );
10972 for ( inode = 0; inode < nodes.size(); ++inode )
10973 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10974 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10977 for ( int i = 0; i < missingBndElems.size(); ++i )
10979 TConnectivity& nodes = missingBndElems[i];
10980 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10983 // 3. Copy present boundary elements
10984 if ( toCopyExistingBondary )
10985 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10987 const SMDS_MeshElement* e = presentBndElems[i];
10988 TConnectivity nodes( e->NbNodes() );
10989 for ( inode = 0; inode < nodes.size(); ++inode )
10990 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10991 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10992 // leave only missing elements in tgtEditor.myLastCreatedElems
10993 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10995 } // loop on given elements
10997 // 4. Fill group with missing boundary elements
11000 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11001 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11002 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11004 tgtEditor.myLastCreatedElems.Clear();
11006 // 5. Copy given elements
11007 if ( toCopyElements )
11009 if (elements.empty())
11010 eIt = aMesh->elementsIterator(elemType);
11012 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11013 while (eIt->more())
11015 const SMDS_MeshElement* elem = eIt->next();
11016 TConnectivity nodes( elem->NbNodes() );
11017 for ( inode = 0; inode < nodes.size(); ++inode )
11018 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11019 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11021 tgtEditor.myLastCreatedElems.Clear();