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 if(elem->GetType() == SMDSAbs_0DElement)
2687 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2688 if ( elem->GetType() == SMDSAbs_Volume )
2690 SMDS_VolumeTool vol( elem );
2691 while ( nodeIt->more() ) {
2692 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2693 if ( theNode != n && vol.IsLinked( theNode, n ))
2694 linkedNodes.insert( n );
2699 for ( int i = 0; nodeIt->more(); ++i ) {
2700 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2701 if ( n == theNode ) {
2702 int iBefore = i - 1;
2704 if ( elem->IsQuadratic() ) {
2705 int nb = elem->NbNodes() / 2;
2706 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2707 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2709 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2710 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2717 //=======================================================================
2718 //function : laplacianSmooth
2719 //purpose : pulls theNode toward the center of surrounding nodes directly
2720 // connected to that node along an element edge
2721 //=======================================================================
2723 void laplacianSmooth(const SMDS_MeshNode* theNode,
2724 const Handle(Geom_Surface)& theSurface,
2725 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2727 // find surrounding nodes
2729 TIDSortedElemSet nodeSet;
2730 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2732 // compute new coodrs
2734 double coord[] = { 0., 0., 0. };
2735 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2736 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2737 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2738 if ( theSurface.IsNull() ) { // smooth in 3D
2739 coord[0] += node->X();
2740 coord[1] += node->Y();
2741 coord[2] += node->Z();
2743 else { // smooth in 2D
2744 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2745 gp_XY* uv = theUVMap[ node ];
2746 coord[0] += uv->X();
2747 coord[1] += uv->Y();
2750 int nbNodes = nodeSet.size();
2753 coord[0] /= nbNodes;
2754 coord[1] /= nbNodes;
2756 if ( !theSurface.IsNull() ) {
2757 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2758 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2759 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2765 coord[2] /= nbNodes;
2769 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2772 //=======================================================================
2773 //function : centroidalSmooth
2774 //purpose : pulls theNode toward the element-area-weighted centroid of the
2775 // surrounding elements
2776 //=======================================================================
2778 void centroidalSmooth(const SMDS_MeshNode* theNode,
2779 const Handle(Geom_Surface)& theSurface,
2780 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2782 gp_XYZ aNewXYZ(0.,0.,0.);
2783 SMESH::Controls::Area anAreaFunc;
2784 double totalArea = 0.;
2789 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2790 while ( elemIt->more() )
2792 const SMDS_MeshElement* elem = elemIt->next();
2795 gp_XYZ elemCenter(0.,0.,0.);
2796 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2797 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2798 int nn = elem->NbNodes();
2799 if(elem->IsQuadratic()) nn = nn/2;
2801 //while ( itN->more() ) {
2803 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2805 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2806 aNodePoints.push_back( aP );
2807 if ( !theSurface.IsNull() ) { // smooth in 2D
2808 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2809 gp_XY* uv = theUVMap[ aNode ];
2810 aP.SetCoord( uv->X(), uv->Y(), 0. );
2814 double elemArea = anAreaFunc.GetValue( aNodePoints );
2815 totalArea += elemArea;
2817 aNewXYZ += elemCenter * elemArea;
2819 aNewXYZ /= totalArea;
2820 if ( !theSurface.IsNull() ) {
2821 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2822 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2827 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2830 //=======================================================================
2831 //function : getClosestUV
2832 //purpose : return UV of closest projection
2833 //=======================================================================
2835 static bool getClosestUV (Extrema_GenExtPS& projector,
2836 const gp_Pnt& point,
2839 projector.Perform( point );
2840 if ( projector.IsDone() ) {
2841 double u, v, minVal = DBL_MAX;
2842 for ( int i = projector.NbExt(); i > 0; i-- )
2843 if ( projector.Value( i ) < minVal ) {
2844 minVal = projector.Value( i );
2845 projector.Point( i ).Parameter( u, v );
2847 result.SetCoord( u, v );
2853 //=======================================================================
2855 //purpose : Smooth theElements during theNbIterations or until a worst
2856 // element has aspect ratio <= theTgtAspectRatio.
2857 // Aspect Ratio varies in range [1.0, inf].
2858 // If theElements is empty, the whole mesh is smoothed.
2859 // theFixedNodes contains additionally fixed nodes. Nodes built
2860 // on edges and boundary nodes are always fixed.
2861 //=======================================================================
2863 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2864 set<const SMDS_MeshNode*> & theFixedNodes,
2865 const SmoothMethod theSmoothMethod,
2866 const int theNbIterations,
2867 double theTgtAspectRatio,
2870 myLastCreatedElems.Clear();
2871 myLastCreatedNodes.Clear();
2873 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2875 if ( theTgtAspectRatio < 1.0 )
2876 theTgtAspectRatio = 1.0;
2878 const double disttol = 1.e-16;
2880 SMESH::Controls::AspectRatio aQualityFunc;
2882 SMESHDS_Mesh* aMesh = GetMeshDS();
2884 if ( theElems.empty() ) {
2885 // add all faces to theElems
2886 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2887 while ( fIt->more() ) {
2888 const SMDS_MeshElement* face = fIt->next();
2889 theElems.insert( face );
2892 // get all face ids theElems are on
2893 set< int > faceIdSet;
2894 TIDSortedElemSet::iterator itElem;
2896 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2897 int fId = FindShape( *itElem );
2898 // check that corresponding submesh exists and a shape is face
2900 faceIdSet.find( fId ) == faceIdSet.end() &&
2901 aMesh->MeshElements( fId )) {
2902 TopoDS_Shape F = aMesh->IndexToShape( fId );
2903 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2904 faceIdSet.insert( fId );
2907 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2909 // ===============================================
2910 // smooth elements on each TopoDS_Face separately
2911 // ===============================================
2913 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2914 for ( ; fId != faceIdSet.rend(); ++fId ) {
2915 // get face surface and submesh
2916 Handle(Geom_Surface) surface;
2917 SMESHDS_SubMesh* faceSubMesh = 0;
2919 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2920 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2921 bool isUPeriodic = false, isVPeriodic = false;
2923 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2924 surface = BRep_Tool::Surface( face );
2925 faceSubMesh = aMesh->MeshElements( *fId );
2926 fToler2 = BRep_Tool::Tolerance( face );
2927 fToler2 *= fToler2 * 10.;
2928 isUPeriodic = surface->IsUPeriodic();
2930 vPeriod = surface->UPeriod();
2931 isVPeriodic = surface->IsVPeriodic();
2933 uPeriod = surface->VPeriod();
2934 surface->Bounds( u1, u2, v1, v2 );
2936 // ---------------------------------------------------------
2937 // for elements on a face, find movable and fixed nodes and
2938 // compute UV for them
2939 // ---------------------------------------------------------
2940 bool checkBoundaryNodes = false;
2941 bool isQuadratic = false;
2942 set<const SMDS_MeshNode*> setMovableNodes;
2943 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2944 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2945 list< const SMDS_MeshElement* > elemsOnFace;
2947 Extrema_GenExtPS projector;
2948 GeomAdaptor_Surface surfAdaptor;
2949 if ( !surface.IsNull() ) {
2950 surfAdaptor.Load( surface );
2951 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2953 int nbElemOnFace = 0;
2954 itElem = theElems.begin();
2955 // loop on not yet smoothed elements: look for elems on a face
2956 while ( itElem != theElems.end() ) {
2957 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2958 break; // all elements found
2960 const SMDS_MeshElement* elem = *itElem;
2961 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2962 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2966 elemsOnFace.push_back( elem );
2967 theElems.erase( itElem++ );
2971 isQuadratic = elem->IsQuadratic();
2973 // get movable nodes of elem
2974 const SMDS_MeshNode* node;
2975 SMDS_TypeOfPosition posType;
2976 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2977 int nn = 0, nbn = elem->NbNodes();
2978 if(elem->IsQuadratic())
2980 while ( nn++ < nbn ) {
2981 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2982 const SMDS_PositionPtr& pos = node->GetPosition();
2983 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2984 if (posType != SMDS_TOP_EDGE &&
2985 posType != SMDS_TOP_VERTEX &&
2986 theFixedNodes.find( node ) == theFixedNodes.end())
2988 // check if all faces around the node are on faceSubMesh
2989 // because a node on edge may be bound to face
2990 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2992 if ( faceSubMesh ) {
2993 while ( eIt->more() && all ) {
2994 const SMDS_MeshElement* e = eIt->next();
2995 all = faceSubMesh->Contains( e );
2999 setMovableNodes.insert( node );
3001 checkBoundaryNodes = true;
3003 if ( posType == SMDS_TOP_3DSPACE )
3004 checkBoundaryNodes = true;
3007 if ( surface.IsNull() )
3010 // get nodes to check UV
3011 list< const SMDS_MeshNode* > uvCheckNodes;
3012 itN = elem->nodesIterator();
3013 nn = 0; nbn = elem->NbNodes();
3014 if(elem->IsQuadratic())
3016 while ( nn++ < nbn ) {
3017 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3018 if ( uvMap.find( node ) == uvMap.end() )
3019 uvCheckNodes.push_back( node );
3020 // add nodes of elems sharing node
3021 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3022 // while ( eIt->more() ) {
3023 // const SMDS_MeshElement* e = eIt->next();
3024 // if ( e != elem ) {
3025 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3026 // while ( nIt->more() ) {
3027 // const SMDS_MeshNode* n =
3028 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3029 // if ( uvMap.find( n ) == uvMap.end() )
3030 // uvCheckNodes.push_back( n );
3036 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3037 for ( ; n != uvCheckNodes.end(); ++n ) {
3040 const SMDS_PositionPtr& pos = node->GetPosition();
3041 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3043 switch ( posType ) {
3044 case SMDS_TOP_FACE: {
3045 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3046 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3049 case SMDS_TOP_EDGE: {
3050 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3051 Handle(Geom2d_Curve) pcurve;
3052 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3053 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3054 if ( !pcurve.IsNull() ) {
3055 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3056 uv = pcurve->Value( u ).XY();
3060 case SMDS_TOP_VERTEX: {
3061 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3062 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3063 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3068 // check existing UV
3069 bool project = true;
3070 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3071 double dist1 = DBL_MAX, dist2 = 0;
3072 if ( posType != SMDS_TOP_3DSPACE ) {
3073 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3074 project = dist1 > fToler2;
3076 if ( project ) { // compute new UV
3078 if ( !getClosestUV( projector, pNode, newUV )) {
3079 MESSAGE("Node Projection Failed " << node);
3083 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3085 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3087 if ( posType != SMDS_TOP_3DSPACE )
3088 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3089 if ( dist2 < dist1 )
3093 // store UV in the map
3094 listUV.push_back( uv );
3095 uvMap.insert( make_pair( node, &listUV.back() ));
3097 } // loop on not yet smoothed elements
3099 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3100 checkBoundaryNodes = true;
3102 // fix nodes on mesh boundary
3104 if ( checkBoundaryNodes ) {
3105 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3106 map< NLink, int >::iterator link_nb;
3107 // put all elements links to linkNbMap
3108 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3109 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3110 const SMDS_MeshElement* elem = (*elemIt);
3111 int nbn = elem->NbNodes();
3112 if(elem->IsQuadratic())
3114 // loop on elem links: insert them in linkNbMap
3115 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3116 for ( int iN = 0; iN < nbn; ++iN ) {
3117 curNode = elem->GetNode( iN );
3119 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3120 else link = make_pair( prevNode , curNode );
3122 link_nb = linkNbMap.find( link );
3123 if ( link_nb == linkNbMap.end() )
3124 linkNbMap.insert( make_pair ( link, 1 ));
3129 // remove nodes that are in links encountered only once from setMovableNodes
3130 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3131 if ( link_nb->second == 1 ) {
3132 setMovableNodes.erase( link_nb->first.first );
3133 setMovableNodes.erase( link_nb->first.second );
3138 // -----------------------------------------------------
3139 // for nodes on seam edge, compute one more UV ( uvMap2 );
3140 // find movable nodes linked to nodes on seam and which
3141 // are to be smoothed using the second UV ( uvMap2 )
3142 // -----------------------------------------------------
3144 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3145 if ( !surface.IsNull() ) {
3146 TopExp_Explorer eExp( face, TopAbs_EDGE );
3147 for ( ; eExp.More(); eExp.Next() ) {
3148 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3149 if ( !BRep_Tool::IsClosed( edge, face ))
3151 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3152 if ( !sm ) continue;
3153 // find out which parameter varies for a node on seam
3156 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3157 if ( pcurve.IsNull() ) continue;
3158 uv1 = pcurve->Value( f );
3160 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3161 if ( pcurve.IsNull() ) continue;
3162 uv2 = pcurve->Value( f );
3163 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3165 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3166 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3168 // get nodes on seam and its vertices
3169 list< const SMDS_MeshNode* > seamNodes;
3170 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3171 while ( nSeamIt->more() ) {
3172 const SMDS_MeshNode* node = nSeamIt->next();
3173 if ( !isQuadratic || !IsMedium( node ))
3174 seamNodes.push_back( node );
3176 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3177 for ( ; vExp.More(); vExp.Next() ) {
3178 sm = aMesh->MeshElements( vExp.Current() );
3180 nSeamIt = sm->GetNodes();
3181 while ( nSeamIt->more() )
3182 seamNodes.push_back( nSeamIt->next() );
3185 // loop on nodes on seam
3186 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3187 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3188 const SMDS_MeshNode* nSeam = *noSeIt;
3189 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3190 if ( n_uv == uvMap.end() )
3193 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3194 // set the second UV
3195 listUV.push_back( *n_uv->second );
3196 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3197 if ( uvMap2.empty() )
3198 uvMap2 = uvMap; // copy the uvMap contents
3199 uvMap2[ nSeam ] = &listUV.back();
3201 // collect movable nodes linked to ones on seam in nodesNearSeam
3202 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3203 while ( eIt->more() ) {
3204 const SMDS_MeshElement* e = eIt->next();
3205 int nbUseMap1 = 0, nbUseMap2 = 0;
3206 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3207 int nn = 0, nbn = e->NbNodes();
3208 if(e->IsQuadratic()) nbn = nbn/2;
3209 while ( nn++ < nbn )
3211 const SMDS_MeshNode* n =
3212 static_cast<const SMDS_MeshNode*>( nIt->next() );
3214 setMovableNodes.find( n ) == setMovableNodes.end() )
3216 // add only nodes being closer to uv2 than to uv1
3217 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3218 0.5 * ( n->Y() + nSeam->Y() ),
3219 0.5 * ( n->Z() + nSeam->Z() ));
3221 getClosestUV( projector, pMid, uv );
3222 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3223 nodesNearSeam.insert( n );
3229 // for centroidalSmooth all element nodes must
3230 // be on one side of a seam
3231 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3232 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3234 while ( nn++ < nbn ) {
3235 const SMDS_MeshNode* n =
3236 static_cast<const SMDS_MeshNode*>( nIt->next() );
3237 setMovableNodes.erase( n );
3241 } // loop on nodes on seam
3242 } // loop on edge of a face
3243 } // if ( !face.IsNull() )
3245 if ( setMovableNodes.empty() ) {
3246 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3247 continue; // goto next face
3255 double maxRatio = -1., maxDisplacement = -1.;
3256 set<const SMDS_MeshNode*>::iterator nodeToMove;
3257 for ( it = 0; it < theNbIterations; it++ ) {
3258 maxDisplacement = 0.;
3259 nodeToMove = setMovableNodes.begin();
3260 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3261 const SMDS_MeshNode* node = (*nodeToMove);
3262 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3265 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3266 if ( theSmoothMethod == LAPLACIAN )
3267 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3269 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3271 // node displacement
3272 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3273 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3274 if ( aDispl > maxDisplacement )
3275 maxDisplacement = aDispl;
3277 // no node movement => exit
3278 //if ( maxDisplacement < 1.e-16 ) {
3279 if ( maxDisplacement < disttol ) {
3280 MESSAGE("-- no node movement --");
3284 // check elements quality
3286 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3287 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3288 const SMDS_MeshElement* elem = (*elemIt);
3289 if ( !elem || elem->GetType() != SMDSAbs_Face )
3291 SMESH::Controls::TSequenceOfXYZ aPoints;
3292 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3293 double aValue = aQualityFunc.GetValue( aPoints );
3294 if ( aValue > maxRatio )
3298 if ( maxRatio <= theTgtAspectRatio ) {
3299 MESSAGE("-- quality achived --");
3302 if (it+1 == theNbIterations) {
3303 MESSAGE("-- Iteration limit exceeded --");
3305 } // smoothing iterations
3307 MESSAGE(" Face id: " << *fId <<
3308 " Nb iterstions: " << it <<
3309 " Displacement: " << maxDisplacement <<
3310 " Aspect Ratio " << maxRatio);
3312 // ---------------------------------------
3313 // new nodes positions are computed,
3314 // record movement in DS and set new UV
3315 // ---------------------------------------
3316 nodeToMove = setMovableNodes.begin();
3317 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3318 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3319 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3320 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3321 if ( node_uv != uvMap.end() ) {
3322 gp_XY* uv = node_uv->second;
3324 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3328 // move medium nodes of quadratic elements
3331 SMESH_MesherHelper helper( *GetMesh() );
3332 if ( !face.IsNull() )
3333 helper.SetSubShape( face );
3334 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3335 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3336 const SMDS_VtkFace* QF =
3337 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3338 if(QF && QF->IsQuadratic()) {
3339 vector<const SMDS_MeshNode*> Ns;
3340 Ns.reserve(QF->NbNodes()+1);
3341 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3342 while ( anIter->more() )
3343 Ns.push_back( cast2Node(anIter->next()) );
3344 Ns.push_back( Ns[0] );
3346 for(int i=0; i<QF->NbNodes(); i=i+2) {
3347 if ( !surface.IsNull() ) {
3348 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3349 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3350 gp_XY uv = ( uv1 + uv2 ) / 2.;
3351 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3352 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3355 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3356 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3357 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3359 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3360 fabs( Ns[i+1]->Y() - y ) > disttol ||
3361 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3362 // we have to move i+1 node
3363 aMesh->MoveNode( Ns[i+1], x, y, z );
3370 } // loop on face ids
3374 //=======================================================================
3375 //function : isReverse
3376 //purpose : Return true if normal of prevNodes is not co-directied with
3377 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3378 // iNotSame is where prevNodes and nextNodes are different
3379 //=======================================================================
3381 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3382 vector<const SMDS_MeshNode*> nextNodes,
3386 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3387 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3389 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3390 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3391 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3392 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3394 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3395 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3396 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3397 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3399 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3401 return (vA ^ vB) * vN < 0.0;
3404 //=======================================================================
3406 * \brief Create elements by sweeping an element
3407 * \param elem - element to sweep
3408 * \param newNodesItVec - nodes generated from each node of the element
3409 * \param newElems - generated elements
3410 * \param nbSteps - number of sweeping steps
3411 * \param srcElements - to append elem for each generated element
3413 //=======================================================================
3415 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3416 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3417 list<const SMDS_MeshElement*>& newElems,
3419 SMESH_SequenceOfElemPtr& srcElements)
3421 //MESSAGE("sweepElement " << nbSteps);
3422 SMESHDS_Mesh* aMesh = GetMeshDS();
3424 // Loop on elem nodes:
3425 // find new nodes and detect same nodes indices
3426 int nbNodes = elem->NbNodes();
3427 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3428 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3429 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3430 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3432 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3433 vector<int> sames(nbNodes);
3434 vector<bool> issimple(nbNodes);
3436 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3437 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3438 const SMDS_MeshNode* node = nnIt->first;
3439 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3440 if ( listNewNodes.empty() ) {
3444 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3446 itNN[ iNode ] = listNewNodes.begin();
3447 prevNod[ iNode ] = node;
3448 nextNod[ iNode ] = listNewNodes.front();
3449 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3450 if ( prevNod[ iNode ] != nextNod [ iNode ])
3451 iNotSameNode = iNode;
3455 sames[nbSame++] = iNode;
3460 //cerr<<" nbSame = "<<nbSame<<endl;
3461 if ( nbSame == nbNodes || nbSame > 2) {
3462 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3463 //INFOS( " Too many same nodes of element " << elem->GetID() );
3467 // if( elem->IsQuadratic() && nbSame>0 ) {
3468 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3472 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3473 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3475 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3476 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3477 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3481 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3482 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3483 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3484 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3486 // check element orientation
3488 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3489 //MESSAGE("Reversed elem " << elem );
3493 std::swap( iBeforeSame, iAfterSame );
3496 // make new elements
3497 const SMDS_MeshElement* lastElem = elem;
3498 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3500 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3501 if(issimple[iNode]) {
3502 nextNod[ iNode ] = *itNN[ iNode ];
3506 if( elem->GetType()==SMDSAbs_Node ) {
3507 // we have to use two nodes
3508 midlNod[ iNode ] = *itNN[ iNode ];
3510 nextNod[ iNode ] = *itNN[ iNode ];
3513 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3514 // we have to use each second node
3516 nextNod[ iNode ] = *itNN[ iNode ];
3520 // we have to use two nodes
3521 midlNod[ iNode ] = *itNN[ iNode ];
3523 nextNod[ iNode ] = *itNN[ iNode ];
3528 SMDS_MeshElement* aNewElem = 0;
3529 if(!elem->IsPoly()) {
3530 switch ( nbNodes ) {
3534 if ( nbSame == 0 ) {
3536 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3538 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3544 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3545 nextNod[ 1 ], nextNod[ 0 ] );
3547 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3548 nextNod[ iNotSameNode ] );
3552 case 3: { // TRIANGLE or quadratic edge
3553 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3555 if ( nbSame == 0 ) // --- pentahedron
3556 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3557 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3559 else if ( nbSame == 1 ) // --- pyramid
3560 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3561 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3562 nextNod[ iSameNode ]);
3564 else // 2 same nodes: --- tetrahedron
3565 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3566 nextNod[ iNotSameNode ]);
3568 else { // quadratic edge
3569 if(nbSame==0) { // quadratic quadrangle
3570 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3571 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3573 else if(nbSame==1) { // quadratic triangle
3575 return; // medium node on axis
3577 else if(sames[0]==0) {
3578 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3579 nextNod[2], midlNod[1], prevNod[2]);
3581 else { // sames[0]==1
3582 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3583 midlNod[0], nextNod[2], prevNod[2]);
3592 case 4: { // QUADRANGLE
3594 if ( nbSame == 0 ) // --- hexahedron
3595 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3596 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3598 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3599 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3600 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3601 nextNod[ iSameNode ]);
3602 newElems.push_back( aNewElem );
3603 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3604 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3605 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3607 else if ( nbSame == 2 ) { // pentahedron
3608 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3609 // iBeforeSame is same too
3610 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3611 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3612 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3614 // iAfterSame is same too
3615 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3616 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3617 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3621 case 6: { // quadratic triangle
3622 // create pentahedron with 15 nodes
3624 if(i0>0) { // reversed case
3625 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3626 nextNod[0], nextNod[2], nextNod[1],
3627 prevNod[5], prevNod[4], prevNod[3],
3628 nextNod[5], nextNod[4], nextNod[3],
3629 midlNod[0], midlNod[2], midlNod[1]);
3631 else { // not reversed case
3632 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3633 nextNod[0], nextNod[1], nextNod[2],
3634 prevNod[3], prevNod[4], prevNod[5],
3635 nextNod[3], nextNod[4], nextNod[5],
3636 midlNod[0], midlNod[1], midlNod[2]);
3639 else if(nbSame==1) {
3640 // 2d order pyramid of 13 nodes
3641 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3642 // int n12,int n23,int n34,int n41,
3643 // int n15,int n25,int n35,int n45, int ID);
3645 int n1,n4,n41,n15,n45;
3646 if(i0>0) { // reversed case
3647 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3648 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3654 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3655 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3660 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3661 nextNod[n4], prevNod[n4], prevNod[n5],
3662 midlNod[n1], nextNod[n41],
3663 midlNod[n4], prevNod[n41],
3664 prevNod[n15], nextNod[n15],
3665 nextNod[n45], prevNod[n45]);
3667 else if(nbSame==2) {
3668 // 2d order tetrahedron of 10 nodes
3669 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3670 // int n12,int n23,int n31,
3671 // int n14,int n24,int n34, int ID);
3672 int n1 = iNotSameNode;
3673 int n2,n3,n12,n23,n31;
3674 if(i0>0) { // reversed case
3675 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3676 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3682 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3683 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3688 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3689 prevNod[n12], prevNod[n23], prevNod[n31],
3690 midlNod[n1], nextNod[n12], nextNod[n31]);
3694 case 8: { // quadratic quadrangle
3696 // create hexahedron with 20 nodes
3697 if(i0>0) { // reversed case
3698 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3699 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3700 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3701 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3702 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3704 else { // not reversed case
3705 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3706 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3707 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3708 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3709 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3712 else if(nbSame==1) {
3713 // --- pyramid + pentahedron - can not be created since it is needed
3714 // additional middle node ot the center of face
3715 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3718 else if(nbSame==2) {
3719 // 2d order Pentahedron with 15 nodes
3720 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3721 // int n12,int n23,int n31,int n45,int n56,int n64,
3722 // int n14,int n25,int n36, int ID);
3724 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3725 // iBeforeSame is same too
3732 // iAfterSame is same too
3738 int n12,n45,n14,n25;
3739 if(i0>0) { //reversed case
3751 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3752 prevNod[n4], prevNod[n5], nextNod[n5],
3753 prevNod[n12], midlNod[n2], nextNod[n12],
3754 prevNod[n45], midlNod[n5], nextNod[n45],
3755 prevNod[n14], prevNod[n25], nextNod[n25]);
3760 // realized for extrusion only
3761 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3762 //vector<int> quantities (nbNodes + 2);
3764 //quantities[0] = nbNodes; // bottom of prism
3765 //for (int inode = 0; inode < nbNodes; inode++) {
3766 // polyedre_nodes[inode] = prevNod[inode];
3769 //quantities[1] = nbNodes; // top of prism
3770 //for (int inode = 0; inode < nbNodes; inode++) {
3771 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3774 //for (int iface = 0; iface < nbNodes; iface++) {
3775 // quantities[iface + 2] = 4;
3776 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3777 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3778 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3779 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3780 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3782 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3789 // realized for extrusion only
3790 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3791 vector<int> quantities (nbNodes + 2);
3793 quantities[0] = nbNodes; // bottom of prism
3794 for (int inode = 0; inode < nbNodes; inode++) {
3795 polyedre_nodes[inode] = prevNod[inode];
3798 quantities[1] = nbNodes; // top of prism
3799 for (int inode = 0; inode < nbNodes; inode++) {
3800 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3803 for (int iface = 0; iface < nbNodes; iface++) {
3804 quantities[iface + 2] = 4;
3805 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3806 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3807 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3808 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3809 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3811 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3815 newElems.push_back( aNewElem );
3816 myLastCreatedElems.Append(aNewElem);
3817 srcElements.Append( elem );
3818 lastElem = aNewElem;
3821 // set new prev nodes
3822 for ( iNode = 0; iNode < nbNodes; iNode++ )
3823 prevNod[ iNode ] = nextNod[ iNode ];
3828 //=======================================================================
3830 * \brief Create 1D and 2D elements around swept elements
3831 * \param mapNewNodes - source nodes and ones generated from them
3832 * \param newElemsMap - source elements and ones generated from them
3833 * \param elemNewNodesMap - nodes generated from each node of each element
3834 * \param elemSet - all swept elements
3835 * \param nbSteps - number of sweeping steps
3836 * \param srcElements - to append elem for each generated element
3838 //=======================================================================
3840 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3841 TElemOfElemListMap & newElemsMap,
3842 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3843 TIDSortedElemSet& elemSet,
3845 SMESH_SequenceOfElemPtr& srcElements)
3847 MESSAGE("makeWalls");
3848 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3849 SMESHDS_Mesh* aMesh = GetMeshDS();
3851 // Find nodes belonging to only one initial element - sweep them to get edges.
3853 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3854 for ( ; nList != mapNewNodes.end(); nList++ ) {
3855 const SMDS_MeshNode* node =
3856 static_cast<const SMDS_MeshNode*>( nList->first );
3857 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3858 int nbInitElems = 0;
3859 const SMDS_MeshElement* el = 0;
3860 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3861 while ( eIt->more() && nbInitElems < 2 ) {
3863 SMDSAbs_ElementType type = el->GetType();
3864 if ( type == SMDSAbs_Volume || type < highType ) continue;
3865 if ( type > highType ) {
3869 if ( elemSet.find(el) != elemSet.end() )
3872 if ( nbInitElems < 2 ) {
3873 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3874 if(!NotCreateEdge) {
3875 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3876 list<const SMDS_MeshElement*> newEdges;
3877 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3882 // Make a ceiling for each element ie an equal element of last new nodes.
3883 // Find free links of faces - make edges and sweep them into faces.
3885 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3886 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3887 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3888 const SMDS_MeshElement* elem = itElem->first;
3889 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3891 if(itElem->second.size()==0) continue;
3893 if ( elem->GetType() == SMDSAbs_Edge ) {
3894 // create a ceiling edge
3895 if (!elem->IsQuadratic()) {
3896 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3897 vecNewNodes[ 1 ]->second.back())) {
3898 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3899 vecNewNodes[ 1 ]->second.back()));
3900 srcElements.Append( myLastCreatedElems.Last() );
3904 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3905 vecNewNodes[ 1 ]->second.back(),
3906 vecNewNodes[ 2 ]->second.back())) {
3907 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3908 vecNewNodes[ 1 ]->second.back(),
3909 vecNewNodes[ 2 ]->second.back()));
3910 srcElements.Append( myLastCreatedElems.Last() );
3914 if ( elem->GetType() != SMDSAbs_Face )
3917 bool hasFreeLinks = false;
3919 TIDSortedElemSet avoidSet;
3920 avoidSet.insert( elem );
3922 set<const SMDS_MeshNode*> aFaceLastNodes;
3923 int iNode, nbNodes = vecNewNodes.size();
3924 if(!elem->IsQuadratic()) {
3925 // loop on the face nodes
3926 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3927 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3928 // look for free links of the face
3929 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3930 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3931 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3932 // check if a link is free
3933 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3934 hasFreeLinks = true;
3935 // make an edge and a ceiling for a new edge
3936 if ( !aMesh->FindEdge( n1, n2 )) {
3937 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3938 srcElements.Append( myLastCreatedElems.Last() );
3940 n1 = vecNewNodes[ iNode ]->second.back();
3941 n2 = vecNewNodes[ iNext ]->second.back();
3942 if ( !aMesh->FindEdge( n1, n2 )) {
3943 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3944 srcElements.Append( myLastCreatedElems.Last() );
3949 else { // elem is quadratic face
3950 int nbn = nbNodes/2;
3951 for ( iNode = 0; iNode < nbn; iNode++ ) {
3952 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3953 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3954 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3955 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3956 // check if a link is free
3957 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3958 hasFreeLinks = true;
3959 // make an edge and a ceiling for a new edge
3961 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3962 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3963 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3964 srcElements.Append( myLastCreatedElems.Last() );
3966 n1 = vecNewNodes[ iNode ]->second.back();
3967 n2 = vecNewNodes[ iNext ]->second.back();
3968 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3969 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3970 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3971 srcElements.Append( myLastCreatedElems.Last() );
3975 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3976 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3980 // sweep free links into faces
3982 if ( hasFreeLinks ) {
3983 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3984 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3986 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3987 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3988 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3989 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3991 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3992 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3994 while ( iVol++ < volNb ) v++;
3995 // find indices of free faces of a volume and their source edges
3996 list< int > freeInd;
3997 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3998 SMDS_VolumeTool vTool( *v );
3999 int iF, nbF = vTool.NbFaces();
4000 for ( iF = 0; iF < nbF; iF ++ ) {
4001 if (vTool.IsFreeFace( iF ) &&
4002 vTool.GetFaceNodes( iF, faceNodeSet ) &&
4003 initNodeSet != faceNodeSet) // except an initial face
4005 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4007 freeInd.push_back( iF );
4008 // find source edge of a free face iF
4009 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4010 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4011 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4012 initNodeSet.begin(), initNodeSet.end(),
4013 commonNodes.begin());
4014 if ( (*v)->IsQuadratic() )
4015 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4017 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4019 if ( !srcEdges.back() )
4021 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4022 << iF << " of volume #" << vTool.ID() << endl;
4027 if ( freeInd.empty() )
4030 // create faces for all steps;
4031 // if such a face has been already created by sweep of edge,
4032 // assure that its orientation is OK
4033 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4035 vTool.SetExternalNormal();
4036 list< int >::iterator ind = freeInd.begin();
4037 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4038 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4040 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4041 int nbn = vTool.NbFaceNodes( *ind );
4043 case 3: { ///// triangle
4044 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4046 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4047 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4049 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4050 aMesh->RemoveElement(f);
4054 case 4: { ///// quadrangle
4055 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4057 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4058 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4060 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4061 aMesh->RemoveElement(f);
4066 if( (*v)->IsQuadratic() ) {
4067 if(nbn==6) { /////// quadratic triangle
4068 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4069 nodes[1], nodes[3], nodes[5] );
4071 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4072 nodes[1], nodes[3], nodes[5]));
4074 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4075 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4076 tmpnodes[0] = nodes[0];
4077 tmpnodes[1] = nodes[2];
4078 tmpnodes[2] = nodes[4];
4079 tmpnodes[3] = nodes[1];
4080 tmpnodes[4] = nodes[3];
4081 tmpnodes[5] = nodes[5];
4082 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4083 nodes[1], nodes[3], nodes[5]));
4084 aMesh->RemoveElement(f);
4087 else { /////// quadratic quadrangle
4088 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4089 nodes[1], nodes[3], nodes[5], nodes[7] );
4091 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4092 nodes[1], nodes[3], nodes[5], nodes[7]));
4094 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4095 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4096 tmpnodes[0] = nodes[0];
4097 tmpnodes[1] = nodes[2];
4098 tmpnodes[2] = nodes[4];
4099 tmpnodes[3] = nodes[6];
4100 tmpnodes[4] = nodes[1];
4101 tmpnodes[5] = nodes[3];
4102 tmpnodes[6] = nodes[5];
4103 tmpnodes[7] = nodes[7];
4104 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4105 nodes[1], nodes[3], nodes[5], nodes[7]));
4106 aMesh->RemoveElement(f);
4110 else { //////// polygon
4111 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4112 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4114 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4115 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4117 // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4118 MESSAGE("ChangeElementNodes");
4119 aMesh->ChangeElementNodes( f, nodes, nbn );
4123 while ( srcElements.Length() < myLastCreatedElems.Length() )
4124 srcElements.Append( *srcEdge );
4126 } // loop on free faces
4128 // go to the next volume
4130 while ( iVol++ < nbVolumesByStep ) v++;
4133 } // sweep free links into faces
4135 // Make a ceiling face with a normal external to a volume
4137 SMDS_VolumeTool lastVol( itElem->second.back() );
4139 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4141 lastVol.SetExternalNormal();
4142 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4143 int nbn = lastVol.NbFaceNodes( iF );
4146 if (!hasFreeLinks ||
4147 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4148 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4151 if (!hasFreeLinks ||
4152 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4153 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4156 if(itElem->second.back()->IsQuadratic()) {
4158 if (!hasFreeLinks ||
4159 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4160 nodes[1], nodes[3], nodes[5]) ) {
4161 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4162 nodes[1], nodes[3], nodes[5]));
4166 if (!hasFreeLinks ||
4167 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4168 nodes[1], nodes[3], nodes[5], nodes[7]) )
4169 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4170 nodes[1], nodes[3], nodes[5], nodes[7]));
4174 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4175 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4176 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4180 while ( srcElements.Length() < myLastCreatedElems.Length() )
4181 srcElements.Append( myLastCreatedElems.Last() );
4183 } // loop on swept elements
4186 //=======================================================================
4187 //function : RotationSweep
4189 //=======================================================================
4191 SMESH_MeshEditor::PGroupIDs
4192 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4193 const gp_Ax1& theAxis,
4194 const double theAngle,
4195 const int theNbSteps,
4196 const double theTol,
4197 const bool theMakeGroups,
4198 const bool theMakeWalls)
4200 myLastCreatedElems.Clear();
4201 myLastCreatedNodes.Clear();
4203 // source elements for each generated one
4204 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4206 MESSAGE( "RotationSweep()");
4208 aTrsf.SetRotation( theAxis, theAngle );
4210 aTrsf2.SetRotation( theAxis, theAngle/2. );
4212 gp_Lin aLine( theAxis );
4213 double aSqTol = theTol * theTol;
4215 SMESHDS_Mesh* aMesh = GetMeshDS();
4217 TNodeOfNodeListMap mapNewNodes;
4218 TElemOfVecOfNnlmiMap mapElemNewNodes;
4219 TElemOfElemListMap newElemsMap;
4222 TIDSortedElemSet::iterator itElem;
4223 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4224 const SMDS_MeshElement* elem = *itElem;
4225 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4227 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4228 newNodesItVec.reserve( elem->NbNodes() );
4230 // loop on elem nodes
4231 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4232 while ( itN->more() ) {
4233 // check if a node has been already sweeped
4234 const SMDS_MeshNode* node = cast2Node( itN->next() );
4236 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4238 aXYZ.Coord( coord[0], coord[1], coord[2] );
4239 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4241 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4242 if ( nIt == mapNewNodes.end() ) {
4243 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4244 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4247 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4249 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4250 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4251 const SMDS_MeshNode * newNode = node;
4252 for ( int i = 0; i < theNbSteps; i++ ) {
4254 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4256 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4257 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4258 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4259 myLastCreatedNodes.Append(newNode);
4260 srcNodes.Append( node );
4261 listNewNodes.push_back( newNode );
4262 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4263 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4266 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4268 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4269 myLastCreatedNodes.Append(newNode);
4270 srcNodes.Append( node );
4271 listNewNodes.push_back( newNode );
4274 listNewNodes.push_back( newNode );
4275 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4276 listNewNodes.push_back( newNode );
4283 // if current elem is quadratic and current node is not medium
4284 // we have to check - may be it is needed to insert additional nodes
4285 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4286 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4287 if(listNewNodes.size()==theNbSteps) {
4288 listNewNodes.clear();
4290 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4292 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4293 const SMDS_MeshNode * newNode = node;
4295 for(int i = 0; i<theNbSteps; i++) {
4296 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4297 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4298 cout<<" 3 AddNode: "<<newNode;
4299 myLastCreatedNodes.Append(newNode);
4300 listNewNodes.push_back( newNode );
4301 srcNodes.Append( node );
4302 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4303 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4304 cout<<" 4 AddNode: "<<newNode;
4305 myLastCreatedNodes.Append(newNode);
4306 srcNodes.Append( node );
4307 listNewNodes.push_back( newNode );
4311 listNewNodes.push_back( newNode );
4317 newNodesItVec.push_back( nIt );
4319 // make new elements
4320 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4324 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4326 PGroupIDs newGroupIDs;
4327 if ( theMakeGroups )
4328 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4334 //=======================================================================
4335 //function : CreateNode
4337 //=======================================================================
4338 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4341 const double tolnode,
4342 SMESH_SequenceOfNode& aNodes)
4344 myLastCreatedElems.Clear();
4345 myLastCreatedNodes.Clear();
4348 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4350 // try to search in sequence of existing nodes
4351 // if aNodes.Length()>0 we 'nave to use given sequence
4352 // else - use all nodes of mesh
4353 if(aNodes.Length()>0) {
4355 for(i=1; i<=aNodes.Length(); i++) {
4356 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4357 if(P1.Distance(P2)<tolnode)
4358 return aNodes.Value(i);
4362 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4363 while(itn->more()) {
4364 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4365 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4366 if(P1.Distance(P2)<tolnode)
4371 // create new node and return it
4372 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4373 myLastCreatedNodes.Append(NewNode);
4378 //=======================================================================
4379 //function : ExtrusionSweep
4381 //=======================================================================
4383 SMESH_MeshEditor::PGroupIDs
4384 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4385 const gp_Vec& theStep,
4386 const int theNbSteps,
4387 TElemOfElemListMap& newElemsMap,
4388 const bool theMakeGroups,
4390 const double theTolerance)
4392 ExtrusParam aParams;
4393 aParams.myDir = gp_Dir(theStep);
4394 aParams.myNodes.Clear();
4395 aParams.mySteps = new TColStd_HSequenceOfReal;
4397 for(i=1; i<=theNbSteps; i++)
4398 aParams.mySteps->Append(theStep.Magnitude());
4401 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4405 //=======================================================================
4406 //function : ExtrusionSweep
4408 //=======================================================================
4410 SMESH_MeshEditor::PGroupIDs
4411 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4412 ExtrusParam& theParams,
4413 TElemOfElemListMap& newElemsMap,
4414 const bool theMakeGroups,
4416 const double theTolerance)
4418 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4419 myLastCreatedElems.Clear();
4420 myLastCreatedNodes.Clear();
4422 // source elements for each generated one
4423 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4425 SMESHDS_Mesh* aMesh = GetMeshDS();
4427 int nbsteps = theParams.mySteps->Length();
4429 TNodeOfNodeListMap mapNewNodes;
4430 //TNodeOfNodeVecMap mapNewNodes;
4431 TElemOfVecOfNnlmiMap mapElemNewNodes;
4432 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4435 TIDSortedElemSet::iterator itElem;
4436 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4437 // check element type
4438 const SMDS_MeshElement* elem = *itElem;
4439 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4442 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4443 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4444 newNodesItVec.reserve( elem->NbNodes() );
4446 // loop on elem nodes
4447 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4448 while ( itN->more() )
4450 // check if a node has been already sweeped
4451 const SMDS_MeshNode* node = cast2Node( itN->next() );
4452 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4453 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4454 if ( nIt == mapNewNodes.end() ) {
4455 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4456 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4457 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4458 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4459 //vecNewNodes.reserve(nbsteps);
4462 double coord[] = { node->X(), node->Y(), node->Z() };
4463 //int nbsteps = theParams.mySteps->Length();
4464 for ( int i = 0; i < nbsteps; i++ ) {
4465 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4466 // create additional node
4467 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4468 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4469 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4470 if( theFlags & EXTRUSION_FLAG_SEW ) {
4471 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4472 theTolerance, theParams.myNodes);
4473 listNewNodes.push_back( newNode );
4476 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4477 myLastCreatedNodes.Append(newNode);
4478 srcNodes.Append( node );
4479 listNewNodes.push_back( newNode );
4482 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4483 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4484 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4485 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4486 if( theFlags & EXTRUSION_FLAG_SEW ) {
4487 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4488 theTolerance, theParams.myNodes);
4489 listNewNodes.push_back( newNode );
4490 //vecNewNodes[i]=newNode;
4493 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4494 myLastCreatedNodes.Append(newNode);
4495 srcNodes.Append( node );
4496 listNewNodes.push_back( newNode );
4497 //vecNewNodes[i]=newNode;
4502 // if current elem is quadratic and current node is not medium
4503 // we have to check - may be it is needed to insert additional nodes
4504 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4505 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4506 if(listNewNodes.size()==nbsteps) {
4507 listNewNodes.clear();
4508 double coord[] = { node->X(), node->Y(), node->Z() };
4509 for ( int i = 0; i < nbsteps; i++ ) {
4510 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4511 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4512 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4513 if( theFlags & EXTRUSION_FLAG_SEW ) {
4514 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4515 theTolerance, theParams.myNodes);
4516 listNewNodes.push_back( newNode );
4519 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4520 myLastCreatedNodes.Append(newNode);
4521 srcNodes.Append( node );
4522 listNewNodes.push_back( newNode );
4524 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4525 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4526 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4527 if( theFlags & EXTRUSION_FLAG_SEW ) {
4528 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4529 theTolerance, theParams.myNodes);
4530 listNewNodes.push_back( newNode );
4533 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4534 myLastCreatedNodes.Append(newNode);
4535 srcNodes.Append( node );
4536 listNewNodes.push_back( newNode );
4542 newNodesItVec.push_back( nIt );
4544 // make new elements
4545 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4548 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4549 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4551 PGroupIDs newGroupIDs;
4552 if ( theMakeGroups )
4553 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4559 //=======================================================================
4560 //class : SMESH_MeshEditor_PathPoint
4561 //purpose : auxiliary class
4562 //=======================================================================
4563 class SMESH_MeshEditor_PathPoint {
4565 SMESH_MeshEditor_PathPoint() {
4566 myPnt.SetCoord(99., 99., 99.);
4567 myTgt.SetCoord(1.,0.,0.);
4571 void SetPnt(const gp_Pnt& aP3D){
4574 void SetTangent(const gp_Dir& aTgt){
4577 void SetAngle(const double& aBeta){
4580 void SetParameter(const double& aPrm){
4583 const gp_Pnt& Pnt()const{
4586 const gp_Dir& Tangent()const{
4589 double Angle()const{
4592 double Parameter()const{
4604 //=======================================================================
4605 //function : ExtrusionAlongTrack
4607 //=======================================================================
4608 SMESH_MeshEditor::Extrusion_Error
4609 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4610 SMESH_subMesh* theTrack,
4611 const SMDS_MeshNode* theN1,
4612 const bool theHasAngles,
4613 list<double>& theAngles,
4614 const bool theLinearVariation,
4615 const bool theHasRefPoint,
4616 const gp_Pnt& theRefPoint,
4617 const bool theMakeGroups)
4619 MESSAGE("ExtrusionAlongTrack");
4620 myLastCreatedElems.Clear();
4621 myLastCreatedNodes.Clear();
4624 std::list<double> aPrms;
4625 TIDSortedElemSet::iterator itElem;
4628 TopoDS_Edge aTrackEdge;
4629 TopoDS_Vertex aV1, aV2;
4631 SMDS_ElemIteratorPtr aItE;
4632 SMDS_NodeIteratorPtr aItN;
4633 SMDSAbs_ElementType aTypeE;
4635 TNodeOfNodeListMap mapNewNodes;
4638 aNbE = theElements.size();
4641 return EXTR_NO_ELEMENTS;
4643 // 1.1 Track Pattern
4646 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4648 aItE = pSubMeshDS->GetElements();
4649 while ( aItE->more() ) {
4650 const SMDS_MeshElement* pE = aItE->next();
4651 aTypeE = pE->GetType();
4652 // Pattern must contain links only
4653 if ( aTypeE != SMDSAbs_Edge )
4654 return EXTR_PATH_NOT_EDGE;
4657 list<SMESH_MeshEditor_PathPoint> fullList;
4659 const TopoDS_Shape& aS = theTrack->GetSubShape();
4660 // Sub shape for the Pattern must be an Edge or Wire
4661 if( aS.ShapeType() == TopAbs_EDGE ) {
4662 aTrackEdge = TopoDS::Edge( aS );
4663 // the Edge must not be degenerated
4664 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4665 return EXTR_BAD_PATH_SHAPE;
4666 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4667 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4668 const SMDS_MeshNode* aN1 = aItN->next();
4669 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4670 const SMDS_MeshNode* aN2 = aItN->next();
4671 // starting node must be aN1 or aN2
4672 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4673 return EXTR_BAD_STARTING_NODE;
4674 aItN = pSubMeshDS->GetNodes();
4675 while ( aItN->more() ) {
4676 const SMDS_MeshNode* pNode = aItN->next();
4677 const SMDS_EdgePosition* pEPos =
4678 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4679 double aT = pEPos->GetUParameter();
4680 aPrms.push_back( aT );
4682 //Extrusion_Error err =
4683 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4685 else if( aS.ShapeType() == TopAbs_WIRE ) {
4686 list< SMESH_subMesh* > LSM;
4687 TopTools_SequenceOfShape Edges;
4688 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4689 while(itSM->more()) {
4690 SMESH_subMesh* SM = itSM->next();
4692 const TopoDS_Shape& aS = SM->GetSubShape();
4695 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4696 int startNid = theN1->GetID();
4697 TColStd_MapOfInteger UsedNums;
4698 int NbEdges = Edges.Length();
4700 for(; i<=NbEdges; i++) {
4702 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4703 for(; itLSM!=LSM.end(); itLSM++) {
4705 if(UsedNums.Contains(k)) continue;
4706 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4707 SMESH_subMesh* locTrack = *itLSM;
4708 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4709 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4710 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4711 const SMDS_MeshNode* aN1 = aItN->next();
4712 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4713 const SMDS_MeshNode* aN2 = aItN->next();
4714 // starting node must be aN1 or aN2
4715 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4716 // 2. Collect parameters on the track edge
4718 aItN = locMeshDS->GetNodes();
4719 while ( aItN->more() ) {
4720 const SMDS_MeshNode* pNode = aItN->next();
4721 const SMDS_EdgePosition* pEPos =
4722 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4723 double aT = pEPos->GetUParameter();
4724 aPrms.push_back( aT );
4726 list<SMESH_MeshEditor_PathPoint> LPP;
4727 //Extrusion_Error err =
4728 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4729 LLPPs.push_back(LPP);
4731 // update startN for search following egde
4732 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4733 else startNid = aN1->GetID();
4737 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4738 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4739 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4740 for(; itPP!=firstList.end(); itPP++) {
4741 fullList.push_back( *itPP );
4743 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4744 fullList.pop_back();
4746 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4747 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4748 itPP = currList.begin();
4749 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4750 gp_Dir D1 = PP1.Tangent();
4751 gp_Dir D2 = PP2.Tangent();
4752 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4753 (D1.Z()+D2.Z())/2 ) );
4754 PP1.SetTangent(Dnew);
4755 fullList.push_back(PP1);
4757 for(; itPP!=firstList.end(); itPP++) {
4758 fullList.push_back( *itPP );
4760 PP1 = fullList.back();
4761 fullList.pop_back();
4763 // if wire not closed
4764 fullList.push_back(PP1);
4768 return EXTR_BAD_PATH_SHAPE;
4771 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4772 theHasRefPoint, theRefPoint, theMakeGroups);
4776 //=======================================================================
4777 //function : ExtrusionAlongTrack
4779 //=======================================================================
4780 SMESH_MeshEditor::Extrusion_Error
4781 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4782 SMESH_Mesh* theTrack,
4783 const SMDS_MeshNode* theN1,
4784 const bool theHasAngles,
4785 list<double>& theAngles,
4786 const bool theLinearVariation,
4787 const bool theHasRefPoint,
4788 const gp_Pnt& theRefPoint,
4789 const bool theMakeGroups)
4791 myLastCreatedElems.Clear();
4792 myLastCreatedNodes.Clear();
4795 std::list<double> aPrms;
4796 TIDSortedElemSet::iterator itElem;
4799 TopoDS_Edge aTrackEdge;
4800 TopoDS_Vertex aV1, aV2;
4802 SMDS_ElemIteratorPtr aItE;
4803 SMDS_NodeIteratorPtr aItN;
4804 SMDSAbs_ElementType aTypeE;
4806 TNodeOfNodeListMap mapNewNodes;
4809 aNbE = theElements.size();
4812 return EXTR_NO_ELEMENTS;
4814 // 1.1 Track Pattern
4817 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4819 aItE = pMeshDS->elementsIterator();
4820 while ( aItE->more() ) {
4821 const SMDS_MeshElement* pE = aItE->next();
4822 aTypeE = pE->GetType();
4823 // Pattern must contain links only
4824 if ( aTypeE != SMDSAbs_Edge )
4825 return EXTR_PATH_NOT_EDGE;
4828 list<SMESH_MeshEditor_PathPoint> fullList;
4830 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4831 // Sub shape for the Pattern must be an Edge or Wire
4832 if( aS.ShapeType() == TopAbs_EDGE ) {
4833 aTrackEdge = TopoDS::Edge( aS );
4834 // the Edge must not be degenerated
4835 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4836 return EXTR_BAD_PATH_SHAPE;
4837 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4838 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4839 const SMDS_MeshNode* aN1 = aItN->next();
4840 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4841 const SMDS_MeshNode* aN2 = aItN->next();
4842 // starting node must be aN1 or aN2
4843 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4844 return EXTR_BAD_STARTING_NODE;
4845 aItN = pMeshDS->nodesIterator();
4846 while ( aItN->more() ) {
4847 const SMDS_MeshNode* pNode = aItN->next();
4848 if( pNode==aN1 || pNode==aN2 ) continue;
4849 const SMDS_EdgePosition* pEPos =
4850 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4851 double aT = pEPos->GetUParameter();
4852 aPrms.push_back( aT );
4854 //Extrusion_Error err =
4855 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4857 else if( aS.ShapeType() == TopAbs_WIRE ) {
4858 list< SMESH_subMesh* > LSM;
4859 TopTools_SequenceOfShape Edges;
4860 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4861 for(; eExp.More(); eExp.Next()) {
4862 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4863 if( BRep_Tool::Degenerated(E) ) continue;
4864 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4870 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4871 int startNid = theN1->GetID();
4872 TColStd_MapOfInteger UsedNums;
4873 int NbEdges = Edges.Length();
4875 for(; i<=NbEdges; i++) {
4877 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4878 for(; itLSM!=LSM.end(); itLSM++) {
4880 if(UsedNums.Contains(k)) continue;
4881 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4882 SMESH_subMesh* locTrack = *itLSM;
4883 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4884 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4885 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4886 const SMDS_MeshNode* aN1 = aItN->next();
4887 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4888 const SMDS_MeshNode* aN2 = aItN->next();
4889 // starting node must be aN1 or aN2
4890 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4891 // 2. Collect parameters on the track edge
4893 aItN = locMeshDS->GetNodes();
4894 while ( aItN->more() ) {
4895 const SMDS_MeshNode* pNode = aItN->next();
4896 const SMDS_EdgePosition* pEPos =
4897 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4898 double aT = pEPos->GetUParameter();
4899 aPrms.push_back( aT );
4901 list<SMESH_MeshEditor_PathPoint> LPP;
4902 //Extrusion_Error err =
4903 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4904 LLPPs.push_back(LPP);
4906 // update startN for search following egde
4907 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4908 else startNid = aN1->GetID();
4912 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4913 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4914 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4915 for(; itPP!=firstList.end(); itPP++) {
4916 fullList.push_back( *itPP );
4918 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4919 fullList.pop_back();
4921 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4922 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4923 itPP = currList.begin();
4924 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4925 gp_Pnt P1 = PP1.Pnt();
4926 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4927 gp_Pnt P2 = PP2.Pnt();
4928 gp_Dir D1 = PP1.Tangent();
4929 gp_Dir D2 = PP2.Tangent();
4930 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4931 (D1.Z()+D2.Z())/2 ) );
4932 PP1.SetTangent(Dnew);
4933 fullList.push_back(PP1);
4935 for(; itPP!=currList.end(); itPP++) {
4936 fullList.push_back( *itPP );
4938 PP1 = fullList.back();
4939 fullList.pop_back();
4941 // if wire not closed
4942 fullList.push_back(PP1);
4946 return EXTR_BAD_PATH_SHAPE;
4949 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4950 theHasRefPoint, theRefPoint, theMakeGroups);
4954 //=======================================================================
4955 //function : MakeEdgePathPoints
4956 //purpose : auxilary for ExtrusionAlongTrack
4957 //=======================================================================
4958 SMESH_MeshEditor::Extrusion_Error
4959 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4960 const TopoDS_Edge& aTrackEdge,
4962 list<SMESH_MeshEditor_PathPoint>& LPP)
4964 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4966 aTolVec2=aTolVec*aTolVec;
4968 TopoDS_Vertex aV1, aV2;
4969 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4970 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4971 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4972 // 2. Collect parameters on the track edge
4973 aPrms.push_front( aT1 );
4974 aPrms.push_back( aT2 );
4977 if( FirstIsStart ) {
4988 SMESH_MeshEditor_PathPoint aPP;
4989 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4990 std::list<double>::iterator aItD = aPrms.begin();
4991 for(; aItD != aPrms.end(); ++aItD) {
4995 aC3D->D1( aT, aP3D, aVec );
4996 aL2 = aVec.SquareMagnitude();
4997 if ( aL2 < aTolVec2 )
4998 return EXTR_CANT_GET_TANGENT;
4999 gp_Dir aTgt( aVec );
5001 aPP.SetTangent( aTgt );
5002 aPP.SetParameter( aT );
5009 //=======================================================================
5010 //function : MakeExtrElements
5011 //purpose : auxilary for ExtrusionAlongTrack
5012 //=======================================================================
5013 SMESH_MeshEditor::Extrusion_Error
5014 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5015 list<SMESH_MeshEditor_PathPoint>& fullList,
5016 const bool theHasAngles,
5017 list<double>& theAngles,
5018 const bool theLinearVariation,
5019 const bool theHasRefPoint,
5020 const gp_Pnt& theRefPoint,
5021 const bool theMakeGroups)
5023 MESSAGE("MakeExtrElements");
5024 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5025 int aNbTP = fullList.size();
5026 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5028 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5029 LinearAngleVariation(aNbTP-1, theAngles);
5031 vector<double> aAngles( aNbTP );
5033 for(; j<aNbTP; ++j) {
5036 if ( theHasAngles ) {
5038 std::list<double>::iterator aItD = theAngles.begin();
5039 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5041 aAngles[j] = anAngle;
5044 // fill vector of path points with angles
5045 //aPPs.resize(fullList.size());
5047 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5048 for(; itPP!=fullList.end(); itPP++) {
5050 SMESH_MeshEditor_PathPoint PP = *itPP;
5051 PP.SetAngle(aAngles[j]);
5055 TNodeOfNodeListMap mapNewNodes;
5056 TElemOfVecOfNnlmiMap mapElemNewNodes;
5057 TElemOfElemListMap newElemsMap;
5058 TIDSortedElemSet::iterator itElem;
5061 SMDSAbs_ElementType aTypeE;
5062 // source elements for each generated one
5063 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5065 // 3. Center of rotation aV0
5066 gp_Pnt aV0 = theRefPoint;
5068 if ( !theHasRefPoint ) {
5070 aGC.SetCoord( 0.,0.,0. );
5072 itElem = theElements.begin();
5073 for ( ; itElem != theElements.end(); itElem++ ) {
5074 const SMDS_MeshElement* elem = *itElem;
5076 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5077 while ( itN->more() ) {
5078 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5083 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5084 list<const SMDS_MeshNode*> aLNx;
5085 mapNewNodes[node] = aLNx;
5087 gp_XYZ aXYZ( aX, aY, aZ );
5095 } // if (!theHasRefPoint) {
5096 mapNewNodes.clear();
5098 // 4. Processing the elements
5099 SMESHDS_Mesh* aMesh = GetMeshDS();
5101 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5102 // check element type
5103 const SMDS_MeshElement* elem = *itElem;
5104 aTypeE = elem->GetType();
5105 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5108 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5109 newNodesItVec.reserve( elem->NbNodes() );
5111 // loop on elem nodes
5113 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5114 while ( itN->more() )
5117 // check if a node has been already processed
5118 const SMDS_MeshNode* node =
5119 static_cast<const SMDS_MeshNode*>( itN->next() );
5120 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5121 if ( nIt == mapNewNodes.end() ) {
5122 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5123 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5126 aX = node->X(); aY = node->Y(); aZ = node->Z();
5128 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5129 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5130 gp_Ax1 anAx1, anAxT1T0;
5131 gp_Dir aDT1x, aDT0x, aDT1T0;
5136 aPN0.SetCoord(aX, aY, aZ);
5138 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5140 aDT0x= aPP0.Tangent();
5141 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5143 for ( j = 1; j < aNbTP; ++j ) {
5144 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5146 aDT1x = aPP1.Tangent();
5147 aAngle1x = aPP1.Angle();
5149 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5151 gp_Vec aV01x( aP0x, aP1x );
5152 aTrsf.SetTranslation( aV01x );
5155 aV1x = aV0x.Transformed( aTrsf );
5156 aPN1 = aPN0.Transformed( aTrsf );
5158 // rotation 1 [ T1,T0 ]
5159 aAngleT1T0=-aDT1x.Angle( aDT0x );
5160 if (fabs(aAngleT1T0) > aTolAng) {
5162 anAxT1T0.SetLocation( aV1x );
5163 anAxT1T0.SetDirection( aDT1T0 );
5164 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5166 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5170 if ( theHasAngles ) {
5171 anAx1.SetLocation( aV1x );
5172 anAx1.SetDirection( aDT1x );
5173 aTrsfRot.SetRotation( anAx1, aAngle1x );
5175 aPN1 = aPN1.Transformed( aTrsfRot );
5179 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5180 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5181 // create additional node
5182 double x = ( aPN1.X() + aPN0.X() )/2.;
5183 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5184 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5185 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5186 myLastCreatedNodes.Append(newNode);
5187 srcNodes.Append( node );
5188 listNewNodes.push_back( newNode );
5193 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5194 myLastCreatedNodes.Append(newNode);
5195 srcNodes.Append( node );
5196 listNewNodes.push_back( newNode );
5206 // if current elem is quadratic and current node is not medium
5207 // we have to check - may be it is needed to insert additional nodes
5208 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5209 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5210 if(listNewNodes.size()==aNbTP-1) {
5211 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5212 gp_XYZ P(node->X(), node->Y(), node->Z());
5213 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5215 for(i=0; i<aNbTP-1; i++) {
5216 const SMDS_MeshNode* N = *it;
5217 double x = ( N->X() + P.X() )/2.;
5218 double y = ( N->Y() + P.Y() )/2.;
5219 double z = ( N->Z() + P.Z() )/2.;
5220 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5221 srcNodes.Append( node );
5222 myLastCreatedNodes.Append(newN);
5225 P = gp_XYZ(N->X(),N->Y(),N->Z());
5227 listNewNodes.clear();
5228 for(i=0; i<2*(aNbTP-1); i++) {
5229 listNewNodes.push_back(aNodes[i]);
5235 newNodesItVec.push_back( nIt );
5237 // make new elements
5238 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5239 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5240 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5243 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5245 if ( theMakeGroups )
5246 generateGroups( srcNodes, srcElems, "extruded");
5252 //=======================================================================
5253 //function : LinearAngleVariation
5254 //purpose : auxilary for ExtrusionAlongTrack
5255 //=======================================================================
5256 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5257 list<double>& Angles)
5259 int nbAngles = Angles.size();
5260 if( nbSteps > nbAngles ) {
5261 vector<double> theAngles(nbAngles);
5262 list<double>::iterator it = Angles.begin();
5264 for(; it!=Angles.end(); it++) {
5266 theAngles[i] = (*it);
5269 double rAn2St = double( nbAngles ) / double( nbSteps );
5270 double angPrev = 0, angle;
5271 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5272 double angCur = rAn2St * ( iSt+1 );
5273 double angCurFloor = floor( angCur );
5274 double angPrevFloor = floor( angPrev );
5275 if ( angPrevFloor == angCurFloor )
5276 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5278 int iP = int( angPrevFloor );
5279 double angPrevCeil = ceil(angPrev);
5280 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5282 int iC = int( angCurFloor );
5283 if ( iC < nbAngles )
5284 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5286 iP = int( angPrevCeil );
5288 angle += theAngles[ iC ];
5290 res.push_back(angle);
5295 for(; it!=res.end(); it++)
5296 Angles.push_back( *it );
5301 //================================================================================
5303 * \brief Move or copy theElements applying theTrsf to their nodes
5304 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5305 * \param theTrsf - transformation to apply
5306 * \param theCopy - if true, create translated copies of theElems
5307 * \param theMakeGroups - if true and theCopy, create translated groups
5308 * \param theTargetMesh - mesh to copy translated elements into
5309 * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5311 //================================================================================
5313 SMESH_MeshEditor::PGroupIDs
5314 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5315 const gp_Trsf& theTrsf,
5317 const bool theMakeGroups,
5318 SMESH_Mesh* theTargetMesh)
5320 myLastCreatedElems.Clear();
5321 myLastCreatedNodes.Clear();
5323 bool needReverse = false;
5324 string groupPostfix;
5325 switch ( theTrsf.Form() ) {
5327 MESSAGE("gp_PntMirror");
5329 groupPostfix = "mirrored";
5332 MESSAGE("gp_Ax1Mirror");
5333 groupPostfix = "mirrored";
5336 MESSAGE("gp_Ax2Mirror");
5338 groupPostfix = "mirrored";
5341 MESSAGE("gp_Rotation");
5342 groupPostfix = "rotated";
5344 case gp_Translation:
5345 MESSAGE("gp_Translation");
5346 groupPostfix = "translated";
5349 MESSAGE("gp_Scale");
5350 groupPostfix = "scaled";
5352 case gp_CompoundTrsf: // different scale by axis
5353 MESSAGE("gp_CompoundTrsf");
5354 groupPostfix = "scaled";
5358 needReverse = false;
5359 groupPostfix = "transformed";
5362 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5363 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5364 SMESHDS_Mesh* aMesh = GetMeshDS();
5367 // map old node to new one
5368 TNodeNodeMap nodeMap;
5370 // elements sharing moved nodes; those of them which have all
5371 // nodes mirrored but are not in theElems are to be reversed
5372 TIDSortedElemSet inverseElemSet;
5374 // source elements for each generated one
5375 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5377 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5378 TIDSortedElemSet orphanNode;
5380 if ( theElems.empty() ) // transform the whole mesh
5383 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5384 while ( eIt->more() ) theElems.insert( eIt->next() );
5386 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5387 while ( nIt->more() )
5389 const SMDS_MeshNode* node = nIt->next();
5390 if ( node->NbInverseElements() == 0)
5391 orphanNode.insert( node );
5395 // loop on elements to transform nodes : first orphan nodes then elems
5396 TIDSortedElemSet::iterator itElem;
5397 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5398 for (int i=0; i<2; i++)
5399 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5400 const SMDS_MeshElement* elem = *itElem;
5404 // loop on elem nodes
5405 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5406 while ( itN->more() ) {
5408 const SMDS_MeshNode* node = cast2Node( itN->next() );
5409 // check if a node has been already transformed
5410 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5411 nodeMap.insert( make_pair ( node, node ));
5412 if ( !n2n_isnew.second )
5416 coord[0] = node->X();
5417 coord[1] = node->Y();
5418 coord[2] = node->Z();
5419 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5420 if ( theTargetMesh ) {
5421 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5422 n2n_isnew.first->second = newNode;
5423 myLastCreatedNodes.Append(newNode);
5424 srcNodes.Append( node );
5426 else if ( theCopy ) {
5427 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5428 n2n_isnew.first->second = newNode;
5429 myLastCreatedNodes.Append(newNode);
5430 srcNodes.Append( node );
5433 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5434 // node position on shape becomes invalid
5435 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5436 ( SMDS_SpacePosition::originSpacePosition() );
5439 // keep inverse elements
5440 if ( !theCopy && !theTargetMesh && needReverse ) {
5441 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5442 while ( invElemIt->more() ) {
5443 const SMDS_MeshElement* iel = invElemIt->next();
5444 inverseElemSet.insert( iel );
5450 // either create new elements or reverse mirrored ones
5451 if ( !theCopy && !needReverse && !theTargetMesh )
5454 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5455 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5456 theElems.insert( *invElemIt );
5458 // replicate or reverse elements
5459 // TODO revoir ordre reverse vtk
5461 REV_TETRA = 0, // = nbNodes - 4
5462 REV_PYRAMID = 1, // = nbNodes - 4
5463 REV_PENTA = 2, // = nbNodes - 4
5465 REV_HEXA = 4, // = nbNodes - 4
5469 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5470 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5471 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5472 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5473 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5474 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5477 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5479 const SMDS_MeshElement* elem = *itElem;
5480 if ( !elem || elem->GetType() == SMDSAbs_Node )
5483 int nbNodes = elem->NbNodes();
5484 int elemType = elem->GetType();
5486 if (elem->IsPoly()) {
5487 // Polygon or Polyhedral Volume
5488 switch ( elemType ) {
5491 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5493 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5494 while (itN->more()) {
5495 const SMDS_MeshNode* node =
5496 static_cast<const SMDS_MeshNode*>(itN->next());
5497 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5498 if (nodeMapIt == nodeMap.end())
5499 break; // not all nodes transformed
5501 // reverse mirrored faces and volumes
5502 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5504 poly_nodes[iNode] = (*nodeMapIt).second;
5508 if ( iNode != nbNodes )
5509 continue; // not all nodes transformed
5511 if ( theTargetMesh ) {
5512 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5513 srcElems.Append( elem );
5515 else if ( theCopy ) {
5516 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5517 srcElems.Append( elem );
5520 aMesh->ChangePolygonNodes(elem, poly_nodes);
5524 case SMDSAbs_Volume:
5526 // ATTENTION: Reversing is not yet done!!!
5527 const SMDS_VtkVolume* aPolyedre =
5528 dynamic_cast<const SMDS_VtkVolume*>( elem );
5530 MESSAGE("Warning: bad volumic element");
5534 vector<const SMDS_MeshNode*> poly_nodes;
5535 vector<int> quantities;
5537 bool allTransformed = true;
5538 int nbFaces = aPolyedre->NbFaces();
5539 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5540 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5541 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5542 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5543 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5544 if (nodeMapIt == nodeMap.end()) {
5545 allTransformed = false; // not all nodes transformed
5547 poly_nodes.push_back((*nodeMapIt).second);
5550 quantities.push_back(nbFaceNodes);
5552 if ( !allTransformed )
5553 continue; // not all nodes transformed
5555 if ( theTargetMesh ) {
5556 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5557 srcElems.Append( elem );
5559 else if ( theCopy ) {
5560 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5561 srcElems.Append( elem );
5564 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5574 int* i = index[ FORWARD ];
5575 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5576 if ( elemType == SMDSAbs_Face )
5577 i = index[ REV_FACE ];
5579 i = index[ nbNodes - 4 ];
5581 if(elem->IsQuadratic()) {
5582 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5585 if(nbNodes==3) { // quadratic edge
5586 static int anIds[] = {1,0,2};
5589 else if(nbNodes==6) { // quadratic triangle
5590 static int anIds[] = {0,2,1,5,4,3};
5593 else if(nbNodes==8) { // quadratic quadrangle
5594 static int anIds[] = {0,3,2,1,7,6,5,4};
5597 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5598 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5601 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5602 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5605 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5606 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5609 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5610 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5616 // find transformed nodes
5617 vector<const SMDS_MeshNode*> nodes(nbNodes);
5619 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5620 while ( itN->more() ) {
5621 const SMDS_MeshNode* node =
5622 static_cast<const SMDS_MeshNode*>( itN->next() );
5623 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5624 if ( nodeMapIt == nodeMap.end() )
5625 break; // not all nodes transformed
5626 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5628 if ( iNode != nbNodes )
5629 continue; // not all nodes transformed
5631 if ( theTargetMesh ) {
5632 if ( SMDS_MeshElement* copy =
5633 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5634 myLastCreatedElems.Append( copy );
5635 srcElems.Append( elem );
5638 else if ( theCopy ) {
5639 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5640 srcElems.Append( elem );
5643 // reverse element as it was reversed by transformation
5645 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5649 PGroupIDs newGroupIDs;
5651 if ( theMakeGroups && theCopy ||
5652 theMakeGroups && theTargetMesh )
5653 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5659 ////=======================================================================
5660 ////function : Scale
5662 ////=======================================================================
5664 //SMESH_MeshEditor::PGroupIDs
5665 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5666 // const gp_Pnt& thePoint,
5667 // const std::list<double>& theScaleFact,
5668 // const bool theCopy,
5669 // const bool theMakeGroups,
5670 // SMESH_Mesh* theTargetMesh)
5672 // MESSAGE("Scale");
5673 // myLastCreatedElems.Clear();
5674 // myLastCreatedNodes.Clear();
5676 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5677 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5678 // SMESHDS_Mesh* aMesh = GetMeshDS();
5680 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5681 // std::list<double>::const_iterator itS = theScaleFact.begin();
5683 // if(theScaleFact.size()==1) {
5687 // if(theScaleFact.size()==2) {
5692 // if(theScaleFact.size()>2) {
5699 // // map old node to new one
5700 // TNodeNodeMap nodeMap;
5702 // // elements sharing moved nodes; those of them which have all
5703 // // nodes mirrored but are not in theElems are to be reversed
5704 // TIDSortedElemSet inverseElemSet;
5706 // // source elements for each generated one
5707 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5709 // // loop on theElems
5710 // TIDSortedElemSet::iterator itElem;
5711 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5712 // const SMDS_MeshElement* elem = *itElem;
5716 // // loop on elem nodes
5717 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5718 // while ( itN->more() ) {
5720 // // check if a node has been already transformed
5721 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5722 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5723 // nodeMap.insert( make_pair ( node, node ));
5724 // if ( !n2n_isnew.second )
5727 // //double coord[3];
5728 // //coord[0] = node->X();
5729 // //coord[1] = node->Y();
5730 // //coord[2] = node->Z();
5731 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5732 // double dx = (node->X() - thePoint.X()) * scaleX;
5733 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5734 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5735 // if ( theTargetMesh ) {
5736 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5737 // const SMDS_MeshNode * newNode =
5738 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5739 // n2n_isnew.first->second = newNode;
5740 // myLastCreatedNodes.Append(newNode);
5741 // srcNodes.Append( node );
5743 // else if ( theCopy ) {
5744 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5745 // const SMDS_MeshNode * newNode =
5746 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5747 // n2n_isnew.first->second = newNode;
5748 // myLastCreatedNodes.Append(newNode);
5749 // srcNodes.Append( node );
5752 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5753 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5754 // // node position on shape becomes invalid
5755 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5756 // ( SMDS_SpacePosition::originSpacePosition() );
5759 // // keep inverse elements
5760 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5761 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5762 // // while ( invElemIt->more() ) {
5763 // // const SMDS_MeshElement* iel = invElemIt->next();
5764 // // inverseElemSet.insert( iel );
5770 // // either create new elements or reverse mirrored ones
5771 // //if ( !theCopy && !needReverse && !theTargetMesh )
5772 // if ( !theCopy && !theTargetMesh )
5773 // return PGroupIDs();
5775 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5776 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5777 // theElems.insert( *invElemIt );
5779 // // replicate or reverse elements
5782 // REV_TETRA = 0, // = nbNodes - 4
5783 // REV_PYRAMID = 1, // = nbNodes - 4
5784 // REV_PENTA = 2, // = nbNodes - 4
5786 // REV_HEXA = 4, // = nbNodes - 4
5789 // int index[][8] = {
5790 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5791 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5792 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5793 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5794 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5795 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5798 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5800 // const SMDS_MeshElement* elem = *itElem;
5801 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5804 // int nbNodes = elem->NbNodes();
5805 // int elemType = elem->GetType();
5807 // if (elem->IsPoly()) {
5808 // // Polygon or Polyhedral Volume
5809 // switch ( elemType ) {
5810 // case SMDSAbs_Face:
5812 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5814 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5815 // while (itN->more()) {
5816 // const SMDS_MeshNode* node =
5817 // static_cast<const SMDS_MeshNode*>(itN->next());
5818 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5819 // if (nodeMapIt == nodeMap.end())
5820 // break; // not all nodes transformed
5821 // //if (needReverse) {
5822 // // // reverse mirrored faces and volumes
5823 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5825 // poly_nodes[iNode] = (*nodeMapIt).second;
5829 // if ( iNode != nbNodes )
5830 // continue; // not all nodes transformed
5832 // if ( theTargetMesh ) {
5833 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5834 // srcElems.Append( elem );
5836 // else if ( theCopy ) {
5837 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5838 // srcElems.Append( elem );
5841 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5845 // case SMDSAbs_Volume:
5847 // // ATTENTION: Reversing is not yet done!!!
5848 // const SMDS_VtkVolume* aPolyedre =
5849 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5850 // if (!aPolyedre) {
5851 // MESSAGE("Warning: bad volumic element");
5855 // vector<const SMDS_MeshNode*> poly_nodes;
5856 // vector<int> quantities;
5858 // bool allTransformed = true;
5859 // int nbFaces = aPolyedre->NbFaces();
5860 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5861 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5862 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5863 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5864 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5865 // if (nodeMapIt == nodeMap.end()) {
5866 // allTransformed = false; // not all nodes transformed
5868 // poly_nodes.push_back((*nodeMapIt).second);
5871 // quantities.push_back(nbFaceNodes);
5873 // if ( !allTransformed )
5874 // continue; // not all nodes transformed
5876 // if ( theTargetMesh ) {
5877 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5878 // srcElems.Append( elem );
5880 // else if ( theCopy ) {
5881 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5882 // srcElems.Append( elem );
5885 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5894 // // Regular elements
5895 // int* i = index[ FORWARD ];
5896 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5897 // // if ( elemType == SMDSAbs_Face )
5898 // // i = index[ REV_FACE ];
5900 // // i = index[ nbNodes - 4 ];
5902 // if(elem->IsQuadratic()) {
5903 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5905 // //if(needReverse) {
5906 // // if(nbNodes==3) { // quadratic edge
5907 // // static int anIds[] = {1,0,2};
5910 // // else if(nbNodes==6) { // quadratic triangle
5911 // // static int anIds[] = {0,2,1,5,4,3};
5914 // // else if(nbNodes==8) { // quadratic quadrangle
5915 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5918 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5919 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5922 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5923 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5926 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5927 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5930 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5931 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5937 // // find transformed nodes
5938 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5940 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5941 // while ( itN->more() ) {
5942 // const SMDS_MeshNode* node =
5943 // static_cast<const SMDS_MeshNode*>( itN->next() );
5944 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5945 // if ( nodeMapIt == nodeMap.end() )
5946 // break; // not all nodes transformed
5947 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5949 // if ( iNode != nbNodes )
5950 // continue; // not all nodes transformed
5952 // if ( theTargetMesh ) {
5953 // if ( SMDS_MeshElement* copy =
5954 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5955 // myLastCreatedElems.Append( copy );
5956 // srcElems.Append( elem );
5959 // else if ( theCopy ) {
5960 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5961 // myLastCreatedElems.Append( copy );
5962 // srcElems.Append( elem );
5966 // // reverse element as it was reversed by transformation
5967 // if ( nbNodes > 2 )
5968 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5972 // PGroupIDs newGroupIDs;
5974 // if ( theMakeGroups && theCopy ||
5975 // theMakeGroups && theTargetMesh ) {
5976 // string groupPostfix = "scaled";
5977 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5980 // return newGroupIDs;
5984 //=======================================================================
5986 * \brief Create groups of elements made during transformation
5987 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5988 * \param elemGens - elements making corresponding myLastCreatedElems
5989 * \param postfix - to append to names of new groups
5991 //=======================================================================
5993 SMESH_MeshEditor::PGroupIDs
5994 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5995 const SMESH_SequenceOfElemPtr& elemGens,
5996 const std::string& postfix,
5997 SMESH_Mesh* targetMesh)
5999 PGroupIDs newGroupIDs( new list<int> );
6000 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6002 // Sort existing groups by types and collect their names
6004 // to store an old group and a generated new one
6005 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6006 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6008 set< string > groupNames;
6010 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6011 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6012 while ( groupIt->more() ) {
6013 SMESH_Group * group = groupIt->next();
6014 if ( !group ) continue;
6015 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6016 if ( !groupDS || groupDS->IsEmpty() ) continue;
6017 groupNames.insert( group->GetName() );
6018 groupDS->SetStoreName( group->GetName() );
6019 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6024 // loop on nodes and elements
6025 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6027 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6028 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6029 if ( gens.Length() != elems.Length() )
6030 throw SALOME_Exception(LOCALIZED("invalid args"));
6032 // loop on created elements
6033 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6035 const SMDS_MeshElement* sourceElem = gens( iElem );
6036 if ( !sourceElem ) {
6037 MESSAGE("generateGroups(): NULL source element");
6040 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6041 if ( groupsOldNew.empty() ) {
6042 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6043 ++iElem; // skip all elements made by sourceElem
6046 // collect all elements made by sourceElem
6047 list< const SMDS_MeshElement* > resultElems;
6048 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6049 if ( resElem != sourceElem )
6050 resultElems.push_back( resElem );
6051 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6052 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6053 if ( resElem != sourceElem )
6054 resultElems.push_back( resElem );
6055 // do not generate element groups from node ones
6056 if ( sourceElem->GetType() == SMDSAbs_Node &&
6057 elems( iElem )->GetType() != SMDSAbs_Node )
6060 // add resultElems to groups made by ones the sourceElem belongs to
6061 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6062 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6064 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6065 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6067 SMDS_MeshGroup* & newGroup = gOldNew->second;
6068 if ( !newGroup )// create a new group
6071 string name = oldGroup->GetStoreName();
6072 if ( !targetMesh ) {
6076 while ( !groupNames.insert( name ).second ) // name exists
6082 TCollection_AsciiString nbStr(nb+1);
6083 name.resize( name.rfind('_')+1 );
6084 name += nbStr.ToCString();
6091 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6093 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6094 newGroup = & groupDS->SMDSGroup();
6095 newGroupIDs->push_back( id );
6098 // fill in a new group
6099 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6100 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6101 newGroup->Add( *resElemIt );
6104 } // loop on created elements
6105 }// loop on nodes and elements
6110 //================================================================================
6112 * \brief Return list of group of nodes close to each other within theTolerance
6113 * Search among theNodes or in the whole mesh if theNodes is empty using
6114 * an Octree algorithm
6116 //================================================================================
6118 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6119 const double theTolerance,
6120 TListOfListOfNodes & theGroupsOfNodes)
6122 myLastCreatedElems.Clear();
6123 myLastCreatedNodes.Clear();
6125 if ( theNodes.empty() )
6126 { // get all nodes in the mesh
6127 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6128 while ( nIt->more() )
6129 theNodes.insert( theNodes.end(),nIt->next());
6132 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6136 //=======================================================================
6138 * \brief Implementation of search for the node closest to point
6140 //=======================================================================
6142 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6144 //---------------------------------------------------------------------
6146 * \brief Constructor
6148 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6150 myMesh = ( SMESHDS_Mesh* ) theMesh;
6152 TIDSortedNodeSet nodes;
6154 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6155 while ( nIt->more() )
6156 nodes.insert( nodes.end(), nIt->next() );
6158 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6160 // get max size of a leaf box
6161 SMESH_OctreeNode* tree = myOctreeNode;
6162 while ( !tree->isLeaf() )
6164 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6168 myHalfLeafSize = tree->maxSize() / 2.;
6171 //---------------------------------------------------------------------
6173 * \brief Move node and update myOctreeNode accordingly
6175 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6177 myOctreeNode->UpdateByMoveNode( node, toPnt );
6178 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6181 //---------------------------------------------------------------------
6183 * \brief Do it's job
6185 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6187 map<double, const SMDS_MeshNode*> dist2Nodes;
6188 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6189 if ( !dist2Nodes.empty() )
6190 return dist2Nodes.begin()->second;
6191 list<const SMDS_MeshNode*> nodes;
6192 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6194 double minSqDist = DBL_MAX;
6195 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6197 // sort leafs by their distance from thePnt
6198 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6199 TDistTreeMap treeMap;
6200 list< SMESH_OctreeNode* > treeList;
6201 list< SMESH_OctreeNode* >::iterator trIt;
6202 treeList.push_back( myOctreeNode );
6204 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6205 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6206 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6208 SMESH_OctreeNode* tree = *trIt;
6209 if ( !tree->isLeaf() ) // put children to the queue
6211 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6212 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6213 while ( cIt->more() )
6214 treeList.push_back( cIt->next() );
6216 else if ( tree->NbNodes() ) // put a tree to the treeMap
6218 const Bnd_B3d& box = tree->getBox();
6219 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6220 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6221 if ( !it_in.second ) // not unique distance to box center
6222 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6225 // find distance after which there is no sense to check tree's
6226 double sqLimit = DBL_MAX;
6227 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6228 if ( treeMap.size() > 5 ) {
6229 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6230 const Bnd_B3d& box = closestTree->getBox();
6231 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6232 sqLimit = limit * limit;
6234 // get all nodes from trees
6235 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6236 if ( sqDist_tree->first > sqLimit )
6238 SMESH_OctreeNode* tree = sqDist_tree->second;
6239 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6242 // find closest among nodes
6243 minSqDist = DBL_MAX;
6244 const SMDS_MeshNode* closestNode = 0;
6245 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6246 for ( ; nIt != nodes.end(); ++nIt ) {
6247 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6248 if ( minSqDist > sqDist ) {
6256 //---------------------------------------------------------------------
6260 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6262 //---------------------------------------------------------------------
6264 * \brief Return the node tree
6266 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6269 SMESH_OctreeNode* myOctreeNode;
6270 SMESHDS_Mesh* myMesh;
6271 double myHalfLeafSize; // max size of a leaf box
6274 //=======================================================================
6276 * \brief Return SMESH_NodeSearcher
6278 //=======================================================================
6280 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6282 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6285 // ========================================================================
6286 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6288 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6289 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6290 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6292 //=======================================================================
6294 * \brief Octal tree of bounding boxes of elements
6296 //=======================================================================
6298 class ElementBndBoxTree : public SMESH_Octree
6302 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6303 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6304 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6305 ~ElementBndBoxTree();
6308 ElementBndBoxTree() {}
6309 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6310 void buildChildrenData();
6311 Bnd_B3d* buildRootBox();
6313 //!< Bounding box of element
6314 struct ElementBox : public Bnd_B3d
6316 const SMDS_MeshElement* _element;
6317 int _refCount; // an ElementBox can be included in several tree branches
6318 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6320 vector< ElementBox* > _elements;
6323 //================================================================================
6325 * \brief ElementBndBoxTree creation
6327 //================================================================================
6329 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6330 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6332 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6333 _elements.reserve( nbElems );
6335 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6336 while ( elemIt->more() )
6337 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6339 if ( _elements.size() > MaxNbElemsInLeaf )
6345 //================================================================================
6349 //================================================================================
6351 ElementBndBoxTree::~ElementBndBoxTree()
6353 for ( int i = 0; i < _elements.size(); ++i )
6354 if ( --_elements[i]->_refCount <= 0 )
6355 delete _elements[i];
6358 //================================================================================
6360 * \brief Return the maximal box
6362 //================================================================================
6364 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6366 Bnd_B3d* box = new Bnd_B3d;
6367 for ( int i = 0; i < _elements.size(); ++i )
6368 box->Add( *_elements[i] );
6372 //================================================================================
6374 * \brief Redistrubute element boxes among children
6376 //================================================================================
6378 void ElementBndBoxTree::buildChildrenData()
6380 for ( int i = 0; i < _elements.size(); ++i )
6382 for (int j = 0; j < 8; j++)
6384 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6386 _elements[i]->_refCount++;
6387 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6390 _elements[i]->_refCount--;
6394 for (int j = 0; j < 8; j++)
6396 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6397 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6398 child->myIsLeaf = true;
6400 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6401 child->_elements.resize( child->_elements.size() ); // compact
6405 //================================================================================
6407 * \brief Return elements which can include the point
6409 //================================================================================
6411 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6412 TIDSortedElemSet& foundElems)
6414 if ( level() && getBox().IsOut( point.XYZ() ))
6419 for ( int i = 0; i < _elements.size(); ++i )
6420 if ( !_elements[i]->IsOut( point.XYZ() ))
6421 foundElems.insert( _elements[i]->_element );
6425 for (int i = 0; i < 8; i++)
6426 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6430 //================================================================================
6432 * \brief Return elements which can be intersected by the line
6434 //================================================================================
6436 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6437 TIDSortedElemSet& foundElems)
6439 if ( level() && getBox().IsOut( line ))
6444 for ( int i = 0; i < _elements.size(); ++i )
6445 if ( !_elements[i]->IsOut( line ))
6446 foundElems.insert( _elements[i]->_element );
6450 for (int i = 0; i < 8; i++)
6451 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6455 //================================================================================
6457 * \brief Construct the element box
6459 //================================================================================
6461 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6465 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6466 while ( nIt->more() )
6467 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6468 Enlarge( tolerance );
6473 //=======================================================================
6475 * \brief Implementation of search for the elements by point and
6476 * of classification of point in 2D mesh
6478 //=======================================================================
6480 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6482 SMESHDS_Mesh* _mesh;
6483 SMDS_ElemIteratorPtr _meshPartIt;
6484 ElementBndBoxTree* _ebbTree;
6485 SMESH_NodeSearcherImpl* _nodeSearcher;
6486 SMDSAbs_ElementType _elementType;
6488 bool _outerFacesFound;
6489 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6491 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6492 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6493 ~SMESH_ElementSearcherImpl()
6495 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6496 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6498 virtual int FindElementsByPoint(const gp_Pnt& point,
6499 SMDSAbs_ElementType type,
6500 vector< const SMDS_MeshElement* >& foundElements);
6501 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6503 void GetElementsNearLine( const gp_Ax1& line,
6504 SMDSAbs_ElementType type,
6505 vector< const SMDS_MeshElement* >& foundElems);
6506 double getTolerance();
6507 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6508 const double tolerance, double & param);
6509 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6510 bool isOuterBoundary(const SMDS_MeshElement* face) const
6512 return _outerFaces.empty() || _outerFaces.count(face);
6514 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6516 const SMDS_MeshElement* _face;
6518 bool _coincides; //!< the line lays in face plane
6519 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6520 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6522 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6525 TIDSortedElemSet _faces;
6526 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6527 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6531 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6533 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6534 << ", _coincides="<<i._coincides << ")";
6537 //=======================================================================
6539 * \brief define tolerance for search
6541 //=======================================================================
6543 double SMESH_ElementSearcherImpl::getTolerance()
6545 if ( _tolerance < 0 )
6547 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6550 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6552 double boxSize = _nodeSearcher->getTree()->maxSize();
6553 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6555 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6557 double boxSize = _ebbTree->maxSize();
6558 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6560 if ( _tolerance == 0 )
6562 // define tolerance by size of a most complex element
6563 int complexType = SMDSAbs_Volume;
6564 while ( complexType > SMDSAbs_All &&
6565 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6567 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6569 if ( complexType == int( SMDSAbs_Node ))
6571 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6573 if ( meshInfo.NbNodes() > 2 )
6574 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6578 SMDS_ElemIteratorPtr elemIt =
6579 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6580 const SMDS_MeshElement* elem = elemIt->next();
6581 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6582 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6584 while ( nodeIt->more() )
6586 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6587 elemSize = max( dist, elemSize );
6590 _tolerance = 1e-4 * elemSize;
6596 //================================================================================
6598 * \brief Find intersection of the line and an edge of face and return parameter on line
6600 //================================================================================
6602 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6603 const SMDS_MeshElement* face,
6610 GeomAPI_ExtremaCurveCurve anExtCC;
6611 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6613 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6614 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6616 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6617 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6618 anExtCC.Init( lineCurve, edge);
6619 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6621 Quantity_Parameter pl, pe;
6622 anExtCC.LowerDistanceParameters( pl, pe );
6624 if ( ++nbInts == 2 )
6628 if ( nbInts > 0 ) param /= nbInts;
6631 //================================================================================
6633 * \brief Find all faces belonging to the outer boundary of mesh
6635 //================================================================================
6637 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6639 if ( _outerFacesFound ) return;
6641 // Collect all outer faces by passing from one outer face to another via their links
6642 // and BTW find out if there are internal faces at all.
6644 // checked links and links where outer boundary meets internal one
6645 set< SMESH_TLink > visitedLinks, seamLinks;
6647 // links to treat with already visited faces sharing them
6648 list < TFaceLink > startLinks;
6650 // load startLinks with the first outerFace
6651 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6652 _outerFaces.insert( outerFace );
6654 TIDSortedElemSet emptySet;
6655 while ( !startLinks.empty() )
6657 const SMESH_TLink& link = startLinks.front()._link;
6658 TIDSortedElemSet& faces = startLinks.front()._faces;
6660 outerFace = *faces.begin();
6661 // find other faces sharing the link
6662 const SMDS_MeshElement* f;
6663 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6666 // select another outer face among the found
6667 const SMDS_MeshElement* outerFace2 = 0;
6668 if ( faces.size() == 2 )
6670 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6672 else if ( faces.size() > 2 )
6674 seamLinks.insert( link );
6676 // link direction within the outerFace
6677 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6678 SMESH_TNodeXYZ( link.node2()));
6679 int i1 = outerFace->GetNodeIndex( link.node1() );
6680 int i2 = outerFace->GetNodeIndex( link.node2() );
6681 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6682 if ( rev ) n1n2.Reverse();
6684 gp_XYZ ofNorm, fNorm;
6685 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6687 // direction from the link inside outerFace
6688 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6689 // sort all other faces by angle with the dirInOF
6690 map< double, const SMDS_MeshElement* > angle2Face;
6691 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6692 for ( ; face != faces.end(); ++face )
6694 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6696 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6697 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6698 if ( angle < 0 ) angle += 2*PI;
6699 angle2Face.insert( make_pair( angle, *face ));
6701 if ( !angle2Face.empty() )
6702 outerFace2 = angle2Face.begin()->second;
6705 // store the found outer face and add its links to continue seaching from
6708 _outerFaces.insert( outerFace );
6709 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6710 for ( int i = 0; i < nbNodes; ++i )
6712 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6713 if ( visitedLinks.insert( link2 ).second )
6714 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6717 startLinks.pop_front();
6719 _outerFacesFound = true;
6721 if ( !seamLinks.empty() )
6723 // There are internal boundaries touching the outher one,
6724 // find all faces of internal boundaries in order to find
6725 // faces of boundaries of holes, if any.
6730 _outerFaces.clear();
6734 //=======================================================================
6736 * \brief Find elements of given type where the given point is IN or ON.
6737 * Returns nb of found elements and elements them-selves.
6739 * 'ALL' type means elements of any type excluding nodes and 0D elements
6741 //=======================================================================
6743 int SMESH_ElementSearcherImpl::
6744 FindElementsByPoint(const gp_Pnt& point,
6745 SMDSAbs_ElementType type,
6746 vector< const SMDS_MeshElement* >& foundElements)
6748 foundElements.clear();
6750 double tolerance = getTolerance();
6752 // =================================================================================
6753 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6755 if ( !_nodeSearcher )
6756 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6758 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6759 if ( !closeNode ) return foundElements.size();
6761 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6762 return foundElements.size(); // to far from any node
6764 if ( type == SMDSAbs_Node )
6766 foundElements.push_back( closeNode );
6770 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6771 while ( elemIt->more() )
6772 foundElements.push_back( elemIt->next() );
6775 // =================================================================================
6776 else // elements more complex than 0D
6778 if ( !_ebbTree || _elementType != type )
6780 if ( _ebbTree ) delete _ebbTree;
6781 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6783 TIDSortedElemSet suspectElems;
6784 _ebbTree->getElementsNearPoint( point, suspectElems );
6785 TIDSortedElemSet::iterator elem = suspectElems.begin();
6786 for ( ; elem != suspectElems.end(); ++elem )
6787 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6788 foundElements.push_back( *elem );
6790 return foundElements.size();
6793 //================================================================================
6795 * \brief Classify the given point in the closed 2D mesh
6797 //================================================================================
6799 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6801 double tolerance = getTolerance();
6802 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6804 if ( _ebbTree ) delete _ebbTree;
6805 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6807 // Algo: analyse transition of a line starting at the point through mesh boundary;
6808 // try three lines parallel to axis of the coordinate system and perform rough
6809 // analysis. If solution is not clear perform thorough analysis.
6811 const int nbAxes = 3;
6812 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6813 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6814 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6815 multimap< int, int > nbInt2Axis; // to find the simplest case
6816 for ( int axis = 0; axis < nbAxes; ++axis )
6818 gp_Ax1 lineAxis( point, axisDir[axis]);
6819 gp_Lin line ( lineAxis );
6821 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6822 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6824 // Intersect faces with the line
6826 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6827 TIDSortedElemSet::iterator face = suspectFaces.begin();
6828 for ( ; face != suspectFaces.end(); ++face )
6832 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6833 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6835 // perform intersection
6836 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6837 if ( !intersection.IsDone() )
6839 if ( intersection.IsInQuadric() )
6841 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6843 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6845 gp_Pnt intersectionPoint = intersection.Point(1);
6846 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6847 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6850 // Analyse intersections roughly
6852 int nbInter = u2inters.size();
6856 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6857 if ( nbInter == 1 ) // not closed mesh
6858 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6860 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6863 if ( (f<0) == (l<0) )
6866 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6867 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6868 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6871 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6873 if ( _outerFacesFound ) break; // pass to thorough analysis
6875 } // three attempts - loop on CS axes
6877 // Analyse intersections thoroughly.
6878 // We make two loops maximum, on the first one we only exclude touching intersections,
6879 // on the second, if situation is still unclear, we gather and use information on
6880 // position of faces (internal or outer). If faces position is already gathered,
6881 // we make the second loop right away.
6883 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6885 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6886 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6888 int axis = nb_axis->second;
6889 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6891 gp_Ax1 lineAxis( point, axisDir[axis]);
6892 gp_Lin line ( lineAxis );
6894 // add tangent intersections to u2inters
6896 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6897 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6898 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6899 u2inters.insert(make_pair( param, *tgtInt ));
6900 tangentInters[ axis ].clear();
6902 // Count intersections before and after the point excluding touching ones.
6903 // If hasPositionInfo we count intersections of outer boundary only
6905 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6906 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6907 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6908 bool ok = ! u_int1->second._coincides;
6909 while ( ok && u_int1 != u2inters.end() )
6911 double u = u_int1->first;
6912 bool touchingInt = false;
6913 if ( ++u_int2 != u2inters.end() )
6915 // skip intersections at the same point (if the line passes through edge or node)
6917 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6923 // skip tangent intersections
6925 const SMDS_MeshElement* prevFace = u_int1->second._face;
6926 while ( ok && u_int2->second._coincides )
6928 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6934 ok = ( u_int2 != u2inters.end() );
6939 // skip intersections at the same point after tangent intersections
6942 double u2 = u_int2->first;
6944 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6950 // decide if we skipped a touching intersection
6951 if ( nbSamePnt + nbTgt > 0 )
6953 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6954 map< double, TInters >::iterator u_int = u_int1;
6955 for ( ; u_int != u_int2; ++u_int )
6957 if ( u_int->second._coincides ) continue;
6958 double dot = u_int->second._faceNorm * line.Direction();
6959 if ( dot > maxDot ) maxDot = dot;
6960 if ( dot < minDot ) minDot = dot;
6962 touchingInt = ( minDot*maxDot < 0 );
6967 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6978 u_int1 = u_int2; // to next intersection
6980 } // loop on intersections with one line
6984 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6987 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6990 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6991 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6993 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6996 if ( (f<0) == (l<0) )
6999 if ( hasPositionInfo )
7000 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7002 } // loop on intersections of the tree lines - thorough analysis
7004 if ( !hasPositionInfo )
7006 // gather info on faces position - is face in the outer boundary or not
7007 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7008 findOuterBoundary( u2inters.begin()->second._face );
7011 } // two attempts - with and w/o faces position info in the mesh
7013 return TopAbs_UNKNOWN;
7016 //=======================================================================
7018 * \brief Return elements possibly intersecting the line
7020 //=======================================================================
7022 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7023 SMDSAbs_ElementType type,
7024 vector< const SMDS_MeshElement* >& foundElems)
7026 if ( !_ebbTree || _elementType != type )
7028 if ( _ebbTree ) delete _ebbTree;
7029 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7031 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7032 _ebbTree->getElementsNearLine( line, suspectFaces );
7033 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7036 //=======================================================================
7038 * \brief Return SMESH_ElementSearcher
7040 //=======================================================================
7042 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7044 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7047 //=======================================================================
7049 * \brief Return SMESH_ElementSearcher
7051 //=======================================================================
7053 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7055 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7058 //=======================================================================
7060 * \brief Return true if the point is IN or ON of the element
7062 //=======================================================================
7064 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7066 if ( element->GetType() == SMDSAbs_Volume)
7068 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7071 // get ordered nodes
7073 vector< gp_XYZ > xyz;
7074 vector<const SMDS_MeshNode*> nodeList;
7076 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7077 if ( element->IsQuadratic() ) {
7078 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7079 nodeIt = f->interlacedNodesElemIterator();
7080 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7081 nodeIt = e->interlacedNodesElemIterator();
7083 while ( nodeIt->more() )
7085 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7086 xyz.push_back( SMESH_TNodeXYZ(node) );
7087 nodeList.push_back(node);
7090 int i, nbNodes = element->NbNodes();
7092 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7094 // compute face normal
7095 gp_Vec faceNorm(0,0,0);
7096 xyz.push_back( xyz.front() );
7097 nodeList.push_back( nodeList.front() );
7098 for ( i = 0; i < nbNodes; ++i )
7100 gp_Vec edge1( xyz[i+1], xyz[i]);
7101 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7102 faceNorm += edge1 ^ edge2;
7104 double normSize = faceNorm.Magnitude();
7105 if ( normSize <= tol )
7107 // degenerated face: point is out if it is out of all face edges
7108 for ( i = 0; i < nbNodes; ++i )
7110 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7111 if ( !isOut( &edge, point, tol ))
7116 faceNorm /= normSize;
7118 // check if the point lays on face plane
7119 gp_Vec n2p( xyz[0], point );
7120 if ( fabs( n2p * faceNorm ) > tol )
7121 return true; // not on face plane
7123 // check if point is out of face boundary:
7124 // define it by closest transition of a ray point->infinity through face boundary
7125 // on the face plane.
7126 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7127 // to find intersections of the ray with the boundary.
7129 gp_Vec plnNorm = ray ^ faceNorm;
7130 normSize = plnNorm.Magnitude();
7131 if ( normSize <= tol ) return false; // point coincides with the first node
7132 plnNorm /= normSize;
7133 // for each node of the face, compute its signed distance to the plane
7134 vector<double> dist( nbNodes + 1);
7135 for ( i = 0; i < nbNodes; ++i )
7137 gp_Vec n2p( xyz[i], point );
7138 dist[i] = n2p * plnNorm;
7140 dist.back() = dist.front();
7141 // find the closest intersection
7143 double rClosest, distClosest = 1e100;;
7145 for ( i = 0; i < nbNodes; ++i )
7148 if ( fabs( dist[i]) < tol )
7150 else if ( fabs( dist[i+1]) < tol )
7152 else if ( dist[i] * dist[i+1] < 0 )
7153 r = dist[i] / ( dist[i] - dist[i+1] );
7155 continue; // no intersection
7156 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7157 gp_Vec p2int ( point, pInt);
7158 if ( p2int * ray > -tol ) // right half-space
7160 double intDist = p2int.SquareMagnitude();
7161 if ( intDist < distClosest )
7166 distClosest = intDist;
7171 return true; // no intesections - out
7173 // analyse transition
7174 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7175 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7176 gp_Vec p2int ( point, pClosest );
7177 bool out = (edgeNorm * p2int) < -tol;
7178 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7181 // ray pass through a face node; analyze transition through an adjacent edge
7182 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7183 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7184 gp_Vec edgeAdjacent( p1, p2 );
7185 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7186 bool out2 = (edgeNorm2 * p2int) < -tol;
7188 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7189 return covexCorner ? (out || out2) : (out && out2);
7191 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7193 // point is out of edge if it is NOT ON any straight part of edge
7194 // (we consider quadratic edge as being composed of two straight parts)
7195 for ( i = 1; i < nbNodes; ++i )
7197 gp_Vec edge( xyz[i-1], xyz[i]);
7198 gp_Vec n1p ( xyz[i-1], point);
7199 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7202 gp_Vec n2p( xyz[i], point );
7203 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7205 return false; // point is ON this part
7209 // Node or 0D element -------------------------------------------------------------------------
7211 gp_Vec n2p ( xyz[0], point );
7212 return n2p.Magnitude() <= tol;
7217 //=======================================================================
7218 //function : SimplifyFace
7220 //=======================================================================
7221 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7222 vector<const SMDS_MeshNode *>& poly_nodes,
7223 vector<int>& quantities) const
7225 int nbNodes = faceNodes.size();
7230 set<const SMDS_MeshNode*> nodeSet;
7232 // get simple seq of nodes
7233 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7234 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7235 int iSimple = 0, nbUnique = 0;
7237 simpleNodes[iSimple++] = faceNodes[0];
7239 for (int iCur = 1; iCur < nbNodes; iCur++) {
7240 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7241 simpleNodes[iSimple++] = faceNodes[iCur];
7242 if (nodeSet.insert( faceNodes[iCur] ).second)
7246 int nbSimple = iSimple;
7247 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7257 bool foundLoop = (nbSimple > nbUnique);
7260 set<const SMDS_MeshNode*> loopSet;
7261 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7262 const SMDS_MeshNode* n = simpleNodes[iSimple];
7263 if (!loopSet.insert( n ).second) {
7267 int iC = 0, curLast = iSimple;
7268 for (; iC < curLast; iC++) {
7269 if (simpleNodes[iC] == n) break;
7271 int loopLen = curLast - iC;
7273 // create sub-element
7275 quantities.push_back(loopLen);
7276 for (; iC < curLast; iC++) {
7277 poly_nodes.push_back(simpleNodes[iC]);
7280 // shift the rest nodes (place from the first loop position)
7281 for (iC = curLast + 1; iC < nbSimple; iC++) {
7282 simpleNodes[iC - loopLen] = simpleNodes[iC];
7284 nbSimple -= loopLen;
7287 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7288 } // while (foundLoop)
7292 quantities.push_back(iSimple);
7293 for (int i = 0; i < iSimple; i++)
7294 poly_nodes.push_back(simpleNodes[i]);
7300 //=======================================================================
7301 //function : MergeNodes
7302 //purpose : In each group, the cdr of nodes are substituted by the first one
7304 //=======================================================================
7306 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7308 MESSAGE("MergeNodes");
7309 myLastCreatedElems.Clear();
7310 myLastCreatedNodes.Clear();
7312 SMESHDS_Mesh* aMesh = GetMeshDS();
7314 TNodeNodeMap nodeNodeMap; // node to replace - new node
7315 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7316 list< int > rmElemIds, rmNodeIds;
7318 // Fill nodeNodeMap and elems
7320 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7321 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7322 list<const SMDS_MeshNode*>& nodes = *grIt;
7323 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7324 const SMDS_MeshNode* nToKeep = *nIt;
7325 //MESSAGE("node to keep " << nToKeep->GetID());
7326 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7327 const SMDS_MeshNode* nToRemove = *nIt;
7328 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7329 if ( nToRemove != nToKeep ) {
7330 //MESSAGE(" node to remove " << nToRemove->GetID());
7331 rmNodeIds.push_back( nToRemove->GetID() );
7332 AddToSameGroups( nToKeep, nToRemove, aMesh );
7335 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7336 while ( invElemIt->more() ) {
7337 const SMDS_MeshElement* elem = invElemIt->next();
7342 // Change element nodes or remove an element
7344 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7345 for ( ; eIt != elems.end(); eIt++ ) {
7346 const SMDS_MeshElement* elem = *eIt;
7347 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7348 int nbNodes = elem->NbNodes();
7349 int aShapeId = FindShape( elem );
7351 set<const SMDS_MeshNode*> nodeSet;
7352 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7353 int iUnique = 0, iCur = 0, nbRepl = 0;
7354 vector<int> iRepl( nbNodes );
7356 // get new seq of nodes
7357 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7358 while ( itN->more() ) {
7359 const SMDS_MeshNode* n =
7360 static_cast<const SMDS_MeshNode*>( itN->next() );
7362 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7363 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7365 // BUG 0020185: begin
7367 bool stopRecur = false;
7368 set<const SMDS_MeshNode*> nodesRecur;
7369 nodesRecur.insert(n);
7370 while (!stopRecur) {
7371 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7372 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7373 n = (*nnIt_i).second;
7374 if (!nodesRecur.insert(n).second) {
7375 // error: recursive dependancy
7384 iRepl[ nbRepl++ ] = iCur;
7386 curNodes[ iCur ] = n;
7387 bool isUnique = nodeSet.insert( n ).second;
7389 uniqueNodes[ iUnique++ ] = n;
7393 // Analyse element topology after replacement
7396 int nbUniqueNodes = nodeSet.size();
7397 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7398 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7399 // Polygons and Polyhedral volumes
7400 if (elem->IsPoly()) {
7402 if (elem->GetType() == SMDSAbs_Face) {
7404 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7406 for (; inode < nbNodes; inode++) {
7407 face_nodes[inode] = curNodes[inode];
7410 vector<const SMDS_MeshNode *> polygons_nodes;
7411 vector<int> quantities;
7412 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7415 for (int iface = 0; iface < nbNew; iface++) {
7416 int nbNodes = quantities[iface];
7417 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7418 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7419 poly_nodes[ii] = polygons_nodes[inode];
7421 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7422 myLastCreatedElems.Append(newElem);
7424 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7427 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7428 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7429 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7431 if (nbNew > 0) quid = nbNew - 1;
7432 vector<int> newquant(quantities.begin()+quid, quantities.end());
7433 const SMDS_MeshElement* newElem = 0;
7434 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7435 myLastCreatedElems.Append(newElem);
7436 if ( aShapeId && newElem )
7437 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7438 rmElemIds.push_back(elem->GetID());
7441 rmElemIds.push_back(elem->GetID());
7445 else if (elem->GetType() == SMDSAbs_Volume) {
7446 // Polyhedral volume
7447 if (nbUniqueNodes < 4) {
7448 rmElemIds.push_back(elem->GetID());
7451 // each face has to be analyzed in order to check volume validity
7452 const SMDS_VtkVolume* aPolyedre =
7453 dynamic_cast<const SMDS_VtkVolume*>( elem );
7455 int nbFaces = aPolyedre->NbFaces();
7457 vector<const SMDS_MeshNode *> poly_nodes;
7458 vector<int> quantities;
7460 for (int iface = 1; iface <= nbFaces; iface++) {
7461 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7462 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7464 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7465 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7466 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7467 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7468 faceNode = (*nnIt).second;
7470 faceNodes[inode - 1] = faceNode;
7473 SimplifyFace(faceNodes, poly_nodes, quantities);
7476 if (quantities.size() > 3) {
7477 // to be done: remove coincident faces
7480 if (quantities.size() > 3)
7482 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7483 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7484 const SMDS_MeshElement* newElem = 0;
7485 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7486 myLastCreatedElems.Append(newElem);
7487 if ( aShapeId && newElem )
7488 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7489 rmElemIds.push_back(elem->GetID());
7493 rmElemIds.push_back(elem->GetID());
7504 // TODO not all the possible cases are solved. Find something more generic?
7505 switch ( nbNodes ) {
7506 case 2: ///////////////////////////////////// EDGE
7507 isOk = false; break;
7508 case 3: ///////////////////////////////////// TRIANGLE
7509 isOk = false; break;
7511 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7513 else { //////////////////////////////////// QUADRANGLE
7514 if ( nbUniqueNodes < 3 )
7516 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7517 isOk = false; // opposite nodes stick
7518 //MESSAGE("isOk " << isOk);
7521 case 6: ///////////////////////////////////// PENTAHEDRON
7522 if ( nbUniqueNodes == 4 ) {
7523 // ---------------------------------> tetrahedron
7525 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7526 // all top nodes stick: reverse a bottom
7527 uniqueNodes[ 0 ] = curNodes [ 1 ];
7528 uniqueNodes[ 1 ] = curNodes [ 0 ];
7530 else if (nbRepl == 3 &&
7531 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7532 // all bottom nodes stick: set a top before
7533 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7534 uniqueNodes[ 0 ] = curNodes [ 3 ];
7535 uniqueNodes[ 1 ] = curNodes [ 4 ];
7536 uniqueNodes[ 2 ] = curNodes [ 5 ];
7538 else if (nbRepl == 4 &&
7539 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7540 // a lateral face turns into a line: reverse a bottom
7541 uniqueNodes[ 0 ] = curNodes [ 1 ];
7542 uniqueNodes[ 1 ] = curNodes [ 0 ];
7547 else if ( nbUniqueNodes == 5 ) {
7548 // PENTAHEDRON --------------------> 2 tetrahedrons
7549 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7550 // a bottom node sticks with a linked top one
7552 SMDS_MeshElement* newElem =
7553 aMesh->AddVolume(curNodes[ 3 ],
7556 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7557 myLastCreatedElems.Append(newElem);
7559 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7560 // 2. : reverse a bottom
7561 uniqueNodes[ 0 ] = curNodes [ 1 ];
7562 uniqueNodes[ 1 ] = curNodes [ 0 ];
7572 if(elem->IsQuadratic()) { // Quadratic quadrangle
7584 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7587 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7589 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7590 uniqueNodes[0] = curNodes[0];
7591 uniqueNodes[1] = curNodes[2];
7592 uniqueNodes[2] = curNodes[3];
7593 uniqueNodes[3] = curNodes[5];
7594 uniqueNodes[4] = curNodes[6];
7595 uniqueNodes[5] = curNodes[7];
7598 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7599 uniqueNodes[0] = curNodes[0];
7600 uniqueNodes[1] = curNodes[1];
7601 uniqueNodes[2] = curNodes[2];
7602 uniqueNodes[3] = curNodes[4];
7603 uniqueNodes[4] = curNodes[5];
7604 uniqueNodes[5] = curNodes[6];
7607 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7608 uniqueNodes[0] = curNodes[1];
7609 uniqueNodes[1] = curNodes[2];
7610 uniqueNodes[2] = curNodes[3];
7611 uniqueNodes[3] = curNodes[5];
7612 uniqueNodes[4] = curNodes[6];
7613 uniqueNodes[5] = curNodes[0];
7616 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7617 uniqueNodes[0] = curNodes[0];
7618 uniqueNodes[1] = curNodes[1];
7619 uniqueNodes[2] = curNodes[3];
7620 uniqueNodes[3] = curNodes[4];
7621 uniqueNodes[4] = curNodes[6];
7622 uniqueNodes[5] = curNodes[7];
7625 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7626 uniqueNodes[0] = curNodes[0];
7627 uniqueNodes[1] = curNodes[2];
7628 uniqueNodes[2] = curNodes[3];
7629 uniqueNodes[3] = curNodes[1];
7630 uniqueNodes[4] = curNodes[6];
7631 uniqueNodes[5] = curNodes[7];
7634 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7635 uniqueNodes[0] = curNodes[0];
7636 uniqueNodes[1] = curNodes[1];
7637 uniqueNodes[2] = curNodes[2];
7638 uniqueNodes[3] = curNodes[4];
7639 uniqueNodes[4] = curNodes[5];
7640 uniqueNodes[5] = curNodes[7];
7643 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7644 uniqueNodes[0] = curNodes[0];
7645 uniqueNodes[1] = curNodes[1];
7646 uniqueNodes[2] = curNodes[3];
7647 uniqueNodes[3] = curNodes[4];
7648 uniqueNodes[4] = curNodes[2];
7649 uniqueNodes[5] = curNodes[7];
7652 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7653 uniqueNodes[0] = curNodes[0];
7654 uniqueNodes[1] = curNodes[1];
7655 uniqueNodes[2] = curNodes[2];
7656 uniqueNodes[3] = curNodes[4];
7657 uniqueNodes[4] = curNodes[5];
7658 uniqueNodes[5] = curNodes[3];
7663 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7666 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7670 //////////////////////////////////// HEXAHEDRON
7672 SMDS_VolumeTool hexa (elem);
7673 hexa.SetExternalNormal();
7674 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7675 //////////////////////// ---> tetrahedron
7676 for ( int iFace = 0; iFace < 6; iFace++ ) {
7677 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7678 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7679 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7680 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7681 // one face turns into a point ...
7682 int iOppFace = hexa.GetOppFaceIndex( iFace );
7683 ind = hexa.GetFaceNodesIndices( iOppFace );
7685 iUnique = 2; // reverse a tetrahedron bottom
7686 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7687 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7689 else if ( iUnique >= 0 )
7690 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7692 if ( nbStick == 1 ) {
7693 // ... and the opposite one - into a triangle.
7695 ind = hexa.GetFaceNodesIndices( iFace );
7696 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7703 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7704 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7705 for ( int iFace = 0; iFace < 6; iFace++ ) {
7706 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7707 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7708 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7709 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7710 // one face turns into a point ...
7711 int iOppFace = hexa.GetOppFaceIndex( iFace );
7712 ind = hexa.GetFaceNodesIndices( iOppFace );
7714 iUnique = 2; // reverse a tetrahedron 1 bottom
7715 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7716 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7718 else if ( iUnique >= 0 )
7719 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7721 if ( nbStick == 0 ) {
7722 // ... and the opposite one is a quadrangle
7724 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7725 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7728 SMDS_MeshElement* newElem =
7729 aMesh->AddVolume(curNodes[ind[ 0 ]],
7732 curNodes[indTop[ 0 ]]);
7733 myLastCreatedElems.Append(newElem);
7735 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7742 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7743 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7744 // find indices of quad and tri faces
7745 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7746 for ( iFace = 0; iFace < 6; iFace++ ) {
7747 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7749 for ( iCur = 0; iCur < 4; iCur++ )
7750 nodeSet.insert( curNodes[ind[ iCur ]] );
7751 nbUniqueNodes = nodeSet.size();
7752 if ( nbUniqueNodes == 3 )
7753 iTriFace[ nbTri++ ] = iFace;
7754 else if ( nbUniqueNodes == 4 )
7755 iQuadFace[ nbQuad++ ] = iFace;
7757 if (nbQuad == 2 && nbTri == 4 &&
7758 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7759 // 2 opposite quadrangles stuck with a diagonal;
7760 // sample groups of merged indices: (0-4)(2-6)
7761 // --------------------------------------------> 2 tetrahedrons
7762 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7763 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7764 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7765 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7766 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7767 // stuck with 0-2 diagonal
7775 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7776 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7777 // stuck with 1-3 diagonal
7789 uniqueNodes[ 0 ] = curNodes [ i0 ];
7790 uniqueNodes[ 1 ] = curNodes [ i1d ];
7791 uniqueNodes[ 2 ] = curNodes [ i3d ];
7792 uniqueNodes[ 3 ] = curNodes [ i0t ];
7795 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7799 myLastCreatedElems.Append(newElem);
7801 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7804 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7805 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7806 // --------------------------------------------> prism
7807 // find 2 opposite triangles
7809 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7810 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7811 // find indices of kept and replaced nodes
7812 // and fill unique nodes of 2 opposite triangles
7813 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7814 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7815 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7816 // fill unique nodes
7819 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7820 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7821 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7823 // iCur of a linked node of the opposite face (make normals co-directed):
7824 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7825 // check that correspondent corners of triangles are linked
7826 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7829 uniqueNodes[ iUnique ] = n;
7830 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7839 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7845 } // switch ( nbNodes )
7847 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7850 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7851 // Change nodes of polyedre
7852 const SMDS_VtkVolume* aPolyedre =
7853 dynamic_cast<const SMDS_VtkVolume*>( elem );
7855 int nbFaces = aPolyedre->NbFaces();
7857 vector<const SMDS_MeshNode *> poly_nodes;
7858 vector<int> quantities (nbFaces);
7860 for (int iface = 1; iface <= nbFaces; iface++) {
7861 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7862 quantities[iface - 1] = nbFaceNodes;
7864 for (inode = 1; inode <= nbFaceNodes; inode++) {
7865 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7867 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7868 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7869 curNode = (*nnIt).second;
7871 poly_nodes.push_back(curNode);
7874 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7878 //int elemId = elem->GetID();
7879 //MESSAGE("Change regular element or polygon " << elemId);
7880 SMDSAbs_ElementType etyp = elem->GetType();
7881 uniqueNodes.resize(nbUniqueNodes);
7882 SMDS_MeshElement* newElem = 0;
7883 if (elem->GetEntityType() == SMDSEntity_Polygon)
7884 newElem = this->AddElement(uniqueNodes, etyp, true);
7886 newElem = this->AddElement(uniqueNodes, etyp, false);
7889 myLastCreatedElems.Append(newElem);
7891 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7893 aMesh->RemoveElement(elem);
7897 // Remove invalid regular element or invalid polygon
7898 //MESSAGE("Remove invalid " << elem->GetID());
7899 rmElemIds.push_back( elem->GetID() );
7902 } // loop on elements
7904 // Remove bad elements, then equal nodes (order important)
7906 Remove( rmElemIds, false );
7907 Remove( rmNodeIds, true );
7912 // ========================================================
7913 // class : SortableElement
7914 // purpose : allow sorting elements basing on their nodes
7915 // ========================================================
7916 class SortableElement : public set <const SMDS_MeshElement*>
7920 SortableElement( const SMDS_MeshElement* theElem )
7923 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7924 while ( nodeIt->more() )
7925 this->insert( nodeIt->next() );
7928 const SMDS_MeshElement* Get() const
7931 void Set(const SMDS_MeshElement* e) const
7936 mutable const SMDS_MeshElement* myElem;
7939 //=======================================================================
7940 //function : FindEqualElements
7941 //purpose : Return list of group of elements built on the same nodes.
7942 // Search among theElements or in the whole mesh if theElements is empty
7943 //=======================================================================
7944 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7945 TListOfListOfElementsID & theGroupsOfElementsID)
7947 myLastCreatedElems.Clear();
7948 myLastCreatedNodes.Clear();
7950 typedef set<const SMDS_MeshElement*> TElemsSet;
7951 typedef map< SortableElement, int > TMapOfNodeSet;
7952 typedef list<int> TGroupOfElems;
7955 if ( theElements.empty() )
7956 { // get all elements in the mesh
7957 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7958 while ( eIt->more() )
7959 elems.insert( elems.end(), eIt->next());
7962 elems = theElements;
7964 vector< TGroupOfElems > arrayOfGroups;
7965 TGroupOfElems groupOfElems;
7966 TMapOfNodeSet mapOfNodeSet;
7968 TElemsSet::iterator elemIt = elems.begin();
7969 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7970 const SMDS_MeshElement* curElem = *elemIt;
7971 SortableElement SE(curElem);
7974 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7975 if( !(pp.second) ) {
7976 TMapOfNodeSet::iterator& itSE = pp.first;
7977 ind = (*itSE).second;
7978 arrayOfGroups[ind].push_back(curElem->GetID());
7981 groupOfElems.clear();
7982 groupOfElems.push_back(curElem->GetID());
7983 arrayOfGroups.push_back(groupOfElems);
7988 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7989 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7990 groupOfElems = *groupIt;
7991 if ( groupOfElems.size() > 1 ) {
7992 groupOfElems.sort();
7993 theGroupsOfElementsID.push_back(groupOfElems);
7998 //=======================================================================
7999 //function : MergeElements
8000 //purpose : In each given group, substitute all elements by the first one.
8001 //=======================================================================
8003 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8005 myLastCreatedElems.Clear();
8006 myLastCreatedNodes.Clear();
8008 typedef list<int> TListOfIDs;
8009 TListOfIDs rmElemIds; // IDs of elems to remove
8011 SMESHDS_Mesh* aMesh = GetMeshDS();
8013 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8014 while ( groupsIt != theGroupsOfElementsID.end() ) {
8015 TListOfIDs& aGroupOfElemID = *groupsIt;
8016 aGroupOfElemID.sort();
8017 int elemIDToKeep = aGroupOfElemID.front();
8018 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8019 aGroupOfElemID.pop_front();
8020 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8021 while ( idIt != aGroupOfElemID.end() ) {
8022 int elemIDToRemove = *idIt;
8023 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8024 // add the kept element in groups of removed one (PAL15188)
8025 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8026 rmElemIds.push_back( elemIDToRemove );
8032 Remove( rmElemIds, false );
8035 //=======================================================================
8036 //function : MergeEqualElements
8037 //purpose : Remove all but one of elements built on the same nodes.
8038 //=======================================================================
8040 void SMESH_MeshEditor::MergeEqualElements()
8042 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8043 to merge equal elements in the whole mesh */
8044 TListOfListOfElementsID aGroupsOfElementsID;
8045 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8046 MergeElements(aGroupsOfElementsID);
8049 //=======================================================================
8050 //function : FindFaceInSet
8051 //purpose : Return a face having linked nodes n1 and n2 and which is
8052 // - not in avoidSet,
8053 // - in elemSet provided that !elemSet.empty()
8054 // i1 and i2 optionally returns indices of n1 and n2
8055 //=======================================================================
8057 const SMDS_MeshElement*
8058 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8059 const SMDS_MeshNode* n2,
8060 const TIDSortedElemSet& elemSet,
8061 const TIDSortedElemSet& avoidSet,
8067 const SMDS_MeshElement* face = 0;
8069 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8070 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8071 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8073 //MESSAGE("in while ( invElemIt->more() && !face )");
8074 const SMDS_MeshElement* elem = invElemIt->next();
8075 if (avoidSet.count( elem ))
8077 if ( !elemSet.empty() && !elemSet.count( elem ))
8080 i1 = elem->GetNodeIndex( n1 );
8081 // find a n2 linked to n1
8082 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8083 for ( int di = -1; di < 2 && !face; di += 2 )
8085 i2 = (i1+di+nbN) % nbN;
8086 if ( elem->GetNode( i2 ) == n2 )
8089 if ( !face && elem->IsQuadratic())
8091 // analysis for quadratic elements using all nodes
8092 const SMDS_VtkFace* F =
8093 dynamic_cast<const SMDS_VtkFace*>(elem);
8094 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8095 // use special nodes iterator
8096 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8097 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8098 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8100 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8101 if ( n1 == prevN && n2 == n )
8105 else if ( n2 == prevN && n1 == n )
8107 face = elem; swap( i1, i2 );
8113 if ( n1ind ) *n1ind = i1;
8114 if ( n2ind ) *n2ind = i2;
8118 //=======================================================================
8119 //function : findAdjacentFace
8121 //=======================================================================
8123 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8124 const SMDS_MeshNode* n2,
8125 const SMDS_MeshElement* elem)
8127 TIDSortedElemSet elemSet, avoidSet;
8129 avoidSet.insert ( elem );
8130 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8133 //=======================================================================
8134 //function : FindFreeBorder
8136 //=======================================================================
8138 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8140 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8141 const SMDS_MeshNode* theSecondNode,
8142 const SMDS_MeshNode* theLastNode,
8143 list< const SMDS_MeshNode* > & theNodes,
8144 list< const SMDS_MeshElement* >& theFaces)
8146 if ( !theFirstNode || !theSecondNode )
8148 // find border face between theFirstNode and theSecondNode
8149 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8153 theFaces.push_back( curElem );
8154 theNodes.push_back( theFirstNode );
8155 theNodes.push_back( theSecondNode );
8157 //vector<const SMDS_MeshNode*> nodes;
8158 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8159 TIDSortedElemSet foundElems;
8160 bool needTheLast = ( theLastNode != 0 );
8162 while ( nStart != theLastNode ) {
8163 if ( nStart == theFirstNode )
8164 return !needTheLast;
8166 // find all free border faces sharing form nStart
8168 list< const SMDS_MeshElement* > curElemList;
8169 list< const SMDS_MeshNode* > nStartList;
8170 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8171 while ( invElemIt->more() ) {
8172 const SMDS_MeshElement* e = invElemIt->next();
8173 if ( e == curElem || foundElems.insert( e ).second ) {
8175 int iNode = 0, nbNodes = e->NbNodes();
8176 //const SMDS_MeshNode* nodes[nbNodes+1];
8177 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8179 if(e->IsQuadratic()) {
8180 const SMDS_VtkFace* F =
8181 dynamic_cast<const SMDS_VtkFace*>(e);
8182 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8183 // use special nodes iterator
8184 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8185 while( anIter->more() ) {
8186 nodes[ iNode++ ] = cast2Node(anIter->next());
8190 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8191 while ( nIt->more() )
8192 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8194 nodes[ iNode ] = nodes[ 0 ];
8196 for ( iNode = 0; iNode < nbNodes; iNode++ )
8197 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8198 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8199 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8201 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8202 curElemList.push_back( e );
8206 // analyse the found
8208 int nbNewBorders = curElemList.size();
8209 if ( nbNewBorders == 0 ) {
8210 // no free border furthermore
8211 return !needTheLast;
8213 else if ( nbNewBorders == 1 ) {
8214 // one more element found
8216 nStart = nStartList.front();
8217 curElem = curElemList.front();
8218 theFaces.push_back( curElem );
8219 theNodes.push_back( nStart );
8222 // several continuations found
8223 list< const SMDS_MeshElement* >::iterator curElemIt;
8224 list< const SMDS_MeshNode* >::iterator nStartIt;
8225 // check if one of them reached the last node
8226 if ( needTheLast ) {
8227 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8228 curElemIt!= curElemList.end();
8229 curElemIt++, nStartIt++ )
8230 if ( *nStartIt == theLastNode ) {
8231 theFaces.push_back( *curElemIt );
8232 theNodes.push_back( *nStartIt );
8236 // find the best free border by the continuations
8237 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8238 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8239 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8240 curElemIt!= curElemList.end();
8241 curElemIt++, nStartIt++ )
8243 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8244 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8245 // find one more free border
8246 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8250 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8251 // choice: clear a worse one
8252 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8253 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8254 contNodes[ iWorse ].clear();
8255 contFaces[ iWorse ].clear();
8258 if ( contNodes[0].empty() && contNodes[1].empty() )
8261 // append the best free border
8262 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8263 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8264 theNodes.pop_back(); // remove nIgnore
8265 theNodes.pop_back(); // remove nStart
8266 theFaces.pop_back(); // remove curElem
8267 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8268 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8269 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8270 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8273 } // several continuations found
8274 } // while ( nStart != theLastNode )
8279 //=======================================================================
8280 //function : CheckFreeBorderNodes
8281 //purpose : Return true if the tree nodes are on a free border
8282 //=======================================================================
8284 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8285 const SMDS_MeshNode* theNode2,
8286 const SMDS_MeshNode* theNode3)
8288 list< const SMDS_MeshNode* > nodes;
8289 list< const SMDS_MeshElement* > faces;
8290 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8293 //=======================================================================
8294 //function : SewFreeBorder
8296 //=======================================================================
8298 SMESH_MeshEditor::Sew_Error
8299 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8300 const SMDS_MeshNode* theBordSecondNode,
8301 const SMDS_MeshNode* theBordLastNode,
8302 const SMDS_MeshNode* theSideFirstNode,
8303 const SMDS_MeshNode* theSideSecondNode,
8304 const SMDS_MeshNode* theSideThirdNode,
8305 const bool theSideIsFreeBorder,
8306 const bool toCreatePolygons,
8307 const bool toCreatePolyedrs)
8309 myLastCreatedElems.Clear();
8310 myLastCreatedNodes.Clear();
8312 MESSAGE("::SewFreeBorder()");
8313 Sew_Error aResult = SEW_OK;
8315 // ====================================
8316 // find side nodes and elements
8317 // ====================================
8319 list< const SMDS_MeshNode* > nSide[ 2 ];
8320 list< const SMDS_MeshElement* > eSide[ 2 ];
8321 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8322 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8326 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8327 nSide[0], eSide[0])) {
8328 MESSAGE(" Free Border 1 not found " );
8329 aResult = SEW_BORDER1_NOT_FOUND;
8331 if (theSideIsFreeBorder) {
8334 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8335 nSide[1], eSide[1])) {
8336 MESSAGE(" Free Border 2 not found " );
8337 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8340 if ( aResult != SEW_OK )
8343 if (!theSideIsFreeBorder) {
8347 // -------------------------------------------------------------------------
8349 // 1. If nodes to merge are not coincident, move nodes of the free border
8350 // from the coord sys defined by the direction from the first to last
8351 // nodes of the border to the correspondent sys of the side 2
8352 // 2. On the side 2, find the links most co-directed with the correspondent
8353 // links of the free border
8354 // -------------------------------------------------------------------------
8356 // 1. Since sewing may break if there are volumes to split on the side 2,
8357 // we wont move nodes but just compute new coordinates for them
8358 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8359 TNodeXYZMap nBordXYZ;
8360 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8361 list< const SMDS_MeshNode* >::iterator nBordIt;
8363 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8364 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8365 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8366 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8367 double tol2 = 1.e-8;
8368 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8369 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8370 // Need node movement.
8372 // find X and Z axes to create trsf
8373 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8375 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8377 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8380 gp_Ax3 toBordAx( Pb1, Zb, X );
8381 gp_Ax3 fromSideAx( Ps1, Zs, X );
8382 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8384 gp_Trsf toBordSys, fromSide2Sys;
8385 toBordSys.SetTransformation( toBordAx );
8386 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8387 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8390 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8391 const SMDS_MeshNode* n = *nBordIt;
8392 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8393 toBordSys.Transforms( xyz );
8394 fromSide2Sys.Transforms( xyz );
8395 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8399 // just insert nodes XYZ in the nBordXYZ map
8400 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8401 const SMDS_MeshNode* n = *nBordIt;
8402 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8406 // 2. On the side 2, find the links most co-directed with the correspondent
8407 // links of the free border
8409 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8410 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8411 sideNodes.push_back( theSideFirstNode );
8413 bool hasVolumes = false;
8414 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8415 set<long> foundSideLinkIDs, checkedLinkIDs;
8416 SMDS_VolumeTool volume;
8417 //const SMDS_MeshNode* faceNodes[ 4 ];
8419 const SMDS_MeshNode* sideNode;
8420 const SMDS_MeshElement* sideElem;
8421 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8422 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8423 nBordIt = bordNodes.begin();
8425 // border node position and border link direction to compare with
8426 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8427 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8428 // choose next side node by link direction or by closeness to
8429 // the current border node:
8430 bool searchByDir = ( *nBordIt != theBordLastNode );
8432 // find the next node on the Side 2
8434 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8436 checkedLinkIDs.clear();
8437 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8439 // loop on inverse elements of current node (prevSideNode) on the Side 2
8440 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8441 while ( invElemIt->more() )
8443 const SMDS_MeshElement* elem = invElemIt->next();
8444 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8445 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8446 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8447 bool isVolume = volume.Set( elem );
8448 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8449 if ( isVolume ) // --volume
8451 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8452 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8453 if(elem->IsQuadratic()) {
8454 const SMDS_VtkFace* F =
8455 dynamic_cast<const SMDS_VtkFace*>(elem);
8456 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8457 // use special nodes iterator
8458 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8459 while( anIter->more() ) {
8460 nodes[ iNode ] = cast2Node(anIter->next());
8461 if ( nodes[ iNode++ ] == prevSideNode )
8462 iPrevNode = iNode - 1;
8466 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8467 while ( nIt->more() ) {
8468 nodes[ iNode ] = cast2Node( nIt->next() );
8469 if ( nodes[ iNode++ ] == prevSideNode )
8470 iPrevNode = iNode - 1;
8473 // there are 2 links to check
8478 // loop on links, to be precise, on the second node of links
8479 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8480 const SMDS_MeshNode* n = nodes[ iNode ];
8482 if ( !volume.IsLinked( n, prevSideNode ))
8486 if ( iNode ) // a node before prevSideNode
8487 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8488 else // a node after prevSideNode
8489 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8491 // check if this link was already used
8492 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8493 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8494 if (!isJustChecked &&
8495 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8497 // test a link geometrically
8498 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8499 bool linkIsBetter = false;
8500 double dot = 0.0, dist = 0.0;
8501 if ( searchByDir ) { // choose most co-directed link
8502 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8503 linkIsBetter = ( dot > maxDot );
8505 else { // choose link with the node closest to bordPos
8506 dist = ( nextXYZ - bordPos ).SquareModulus();
8507 linkIsBetter = ( dist < minDist );
8509 if ( linkIsBetter ) {
8518 } // loop on inverse elements of prevSideNode
8521 MESSAGE(" Cant find path by links of the Side 2 ");
8522 return SEW_BAD_SIDE_NODES;
8524 sideNodes.push_back( sideNode );
8525 sideElems.push_back( sideElem );
8526 foundSideLinkIDs.insert ( linkID );
8527 prevSideNode = sideNode;
8529 if ( *nBordIt == theBordLastNode )
8530 searchByDir = false;
8532 // find the next border link to compare with
8533 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8534 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8535 // move to next border node if sideNode is before forward border node (bordPos)
8536 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8537 prevBordNode = *nBordIt;
8539 bordPos = nBordXYZ[ *nBordIt ];
8540 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8541 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8545 while ( sideNode != theSideSecondNode );
8547 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8548 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8549 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8551 } // end nodes search on the side 2
8553 // ============================
8554 // sew the border to the side 2
8555 // ============================
8557 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8558 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8560 TListOfListOfNodes nodeGroupsToMerge;
8561 if ( nbNodes[0] == nbNodes[1] ||
8562 ( theSideIsFreeBorder && !theSideThirdNode)) {
8564 // all nodes are to be merged
8566 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8567 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8568 nIt[0]++, nIt[1]++ )
8570 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8571 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8572 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8577 // insert new nodes into the border and the side to get equal nb of segments
8579 // get normalized parameters of nodes on the borders
8580 //double param[ 2 ][ maxNbNodes ];
8582 param[0] = new double [ maxNbNodes ];
8583 param[1] = new double [ maxNbNodes ];
8585 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8586 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8587 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8588 const SMDS_MeshNode* nPrev = *nIt;
8589 double bordLength = 0;
8590 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8591 const SMDS_MeshNode* nCur = *nIt;
8592 gp_XYZ segment (nCur->X() - nPrev->X(),
8593 nCur->Y() - nPrev->Y(),
8594 nCur->Z() - nPrev->Z());
8595 double segmentLen = segment.Modulus();
8596 bordLength += segmentLen;
8597 param[ iBord ][ iNode ] = bordLength;
8600 // normalize within [0,1]
8601 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8602 param[ iBord ][ iNode ] /= bordLength;
8606 // loop on border segments
8607 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8608 int i[ 2 ] = { 0, 0 };
8609 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8610 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8612 TElemOfNodeListMap insertMap;
8613 TElemOfNodeListMap::iterator insertMapIt;
8615 // key: elem to insert nodes into
8616 // value: 2 nodes to insert between + nodes to be inserted
8618 bool next[ 2 ] = { false, false };
8620 // find min adjacent segment length after sewing
8621 double nextParam = 10., prevParam = 0;
8622 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8623 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8624 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8625 if ( i[ iBord ] > 0 )
8626 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8628 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8629 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8630 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8632 // choose to insert or to merge nodes
8633 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8634 if ( Abs( du ) <= minSegLen * 0.2 ) {
8637 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8638 const SMDS_MeshNode* n0 = *nIt[0];
8639 const SMDS_MeshNode* n1 = *nIt[1];
8640 nodeGroupsToMerge.back().push_back( n1 );
8641 nodeGroupsToMerge.back().push_back( n0 );
8642 // position of node of the border changes due to merge
8643 param[ 0 ][ i[0] ] += du;
8644 // move n1 for the sake of elem shape evaluation during insertion.
8645 // n1 will be removed by MergeNodes() anyway
8646 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8647 next[0] = next[1] = true;
8652 int intoBord = ( du < 0 ) ? 0 : 1;
8653 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8654 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8655 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8656 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8657 if ( intoBord == 1 ) {
8658 // move node of the border to be on a link of elem of the side
8659 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8660 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8661 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8662 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8663 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8665 insertMapIt = insertMap.find( elem );
8666 bool notFound = ( insertMapIt == insertMap.end() );
8667 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8669 // insert into another link of the same element:
8670 // 1. perform insertion into the other link of the elem
8671 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8672 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8673 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8674 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8675 // 2. perform insertion into the link of adjacent faces
8677 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8679 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8683 if (toCreatePolyedrs) {
8684 // perform insertion into the links of adjacent volumes
8685 UpdateVolumes(n12, n22, nodeList);
8687 // 3. find an element appeared on n1 and n2 after the insertion
8688 insertMap.erase( elem );
8689 elem = findAdjacentFace( n1, n2, 0 );
8691 if ( notFound || otherLink ) {
8692 // add element and nodes of the side into the insertMap
8693 insertMapIt = insertMap.insert
8694 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8695 (*insertMapIt).second.push_back( n1 );
8696 (*insertMapIt).second.push_back( n2 );
8698 // add node to be inserted into elem
8699 (*insertMapIt).second.push_back( nIns );
8700 next[ 1 - intoBord ] = true;
8703 // go to the next segment
8704 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8705 if ( next[ iBord ] ) {
8706 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8708 nPrev[ iBord ] = *nIt[ iBord ];
8709 nIt[ iBord ]++; i[ iBord ]++;
8713 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8715 // perform insertion of nodes into elements
8717 for (insertMapIt = insertMap.begin();
8718 insertMapIt != insertMap.end();
8721 const SMDS_MeshElement* elem = (*insertMapIt).first;
8722 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8723 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8724 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8726 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8728 if ( !theSideIsFreeBorder ) {
8729 // look for and insert nodes into the faces adjacent to elem
8731 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8733 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8738 if (toCreatePolyedrs) {
8739 // perform insertion into the links of adjacent volumes
8740 UpdateVolumes(n1, n2, nodeList);
8746 } // end: insert new nodes
8748 MergeNodes ( nodeGroupsToMerge );
8753 //=======================================================================
8754 //function : InsertNodesIntoLink
8755 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8756 // and theBetweenNode2 and split theElement
8757 //=======================================================================
8759 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8760 const SMDS_MeshNode* theBetweenNode1,
8761 const SMDS_MeshNode* theBetweenNode2,
8762 list<const SMDS_MeshNode*>& theNodesToInsert,
8763 const bool toCreatePoly)
8765 if ( theFace->GetType() != SMDSAbs_Face ) return;
8767 // find indices of 2 link nodes and of the rest nodes
8768 int iNode = 0, il1, il2, i3, i4;
8769 il1 = il2 = i3 = i4 = -1;
8770 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8771 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8773 if(theFace->IsQuadratic()) {
8774 const SMDS_VtkFace* F =
8775 dynamic_cast<const SMDS_VtkFace*>(theFace);
8776 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8777 // use special nodes iterator
8778 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8779 while( anIter->more() ) {
8780 const SMDS_MeshNode* n = cast2Node(anIter->next());
8781 if ( n == theBetweenNode1 )
8783 else if ( n == theBetweenNode2 )
8789 nodes[ iNode++ ] = n;
8793 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8794 while ( nodeIt->more() ) {
8795 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8796 if ( n == theBetweenNode1 )
8798 else if ( n == theBetweenNode2 )
8804 nodes[ iNode++ ] = n;
8807 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8810 // arrange link nodes to go one after another regarding the face orientation
8811 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8812 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8817 aNodesToInsert.reverse();
8819 // check that not link nodes of a quadrangles are in good order
8820 int nbFaceNodes = theFace->NbNodes();
8821 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8827 if (toCreatePoly || theFace->IsPoly()) {
8830 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8832 // add nodes of face up to first node of link
8835 if(theFace->IsQuadratic()) {
8836 const SMDS_VtkFace* F =
8837 dynamic_cast<const SMDS_VtkFace*>(theFace);
8838 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8839 // use special nodes iterator
8840 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8841 while( anIter->more() && !isFLN ) {
8842 const SMDS_MeshNode* n = cast2Node(anIter->next());
8843 poly_nodes[iNode++] = n;
8844 if (n == nodes[il1]) {
8848 // add nodes to insert
8849 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8850 for (; nIt != aNodesToInsert.end(); nIt++) {
8851 poly_nodes[iNode++] = *nIt;
8853 // add nodes of face starting from last node of link
8854 while ( anIter->more() ) {
8855 poly_nodes[iNode++] = cast2Node(anIter->next());
8859 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8860 while ( nodeIt->more() && !isFLN ) {
8861 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8862 poly_nodes[iNode++] = n;
8863 if (n == nodes[il1]) {
8867 // add nodes to insert
8868 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8869 for (; nIt != aNodesToInsert.end(); nIt++) {
8870 poly_nodes[iNode++] = *nIt;
8872 // add nodes of face starting from last node of link
8873 while ( nodeIt->more() ) {
8874 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8875 poly_nodes[iNode++] = n;
8879 // edit or replace the face
8880 SMESHDS_Mesh *aMesh = GetMeshDS();
8882 if (theFace->IsPoly()) {
8883 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8886 int aShapeId = FindShape( theFace );
8888 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8889 myLastCreatedElems.Append(newElem);
8890 if ( aShapeId && newElem )
8891 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8893 aMesh->RemoveElement(theFace);
8898 SMESHDS_Mesh *aMesh = GetMeshDS();
8899 if( !theFace->IsQuadratic() ) {
8901 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8902 int nbLinkNodes = 2 + aNodesToInsert.size();
8903 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8904 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8905 linkNodes[ 0 ] = nodes[ il1 ];
8906 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8907 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8908 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8909 linkNodes[ iNode++ ] = *nIt;
8911 // decide how to split a quadrangle: compare possible variants
8912 // and choose which of splits to be a quadrangle
8913 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8914 if ( nbFaceNodes == 3 ) {
8915 iBestQuad = nbSplits;
8918 else if ( nbFaceNodes == 4 ) {
8919 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8920 double aBestRate = DBL_MAX;
8921 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8923 double aBadRate = 0;
8924 // evaluate elements quality
8925 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8926 if ( iSplit == iQuad ) {
8927 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8931 aBadRate += getBadRate( &quad, aCrit );
8934 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8936 nodes[ iSplit < iQuad ? i4 : i3 ]);
8937 aBadRate += getBadRate( &tria, aCrit );
8941 if ( aBadRate < aBestRate ) {
8943 aBestRate = aBadRate;
8948 // create new elements
8949 int aShapeId = FindShape( theFace );
8952 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8953 SMDS_MeshElement* newElem = 0;
8954 if ( iSplit == iBestQuad )
8955 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8960 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8962 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8963 myLastCreatedElems.Append(newElem);
8964 if ( aShapeId && newElem )
8965 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8968 // change nodes of theFace
8969 const SMDS_MeshNode* newNodes[ 4 ];
8970 newNodes[ 0 ] = linkNodes[ i1 ];
8971 newNodes[ 1 ] = linkNodes[ i2 ];
8972 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8973 newNodes[ 3 ] = nodes[ i4 ];
8974 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8975 const SMDS_MeshElement* newElem = 0;
8976 if (iSplit == iBestQuad)
8977 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8979 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8980 myLastCreatedElems.Append(newElem);
8981 if ( aShapeId && newElem )
8982 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8983 } // end if(!theFace->IsQuadratic())
8984 else { // theFace is quadratic
8985 // we have to split theFace on simple triangles and one simple quadrangle
8987 int nbshift = tmp*2;
8988 // shift nodes in nodes[] by nbshift
8990 for(i=0; i<nbshift; i++) {
8991 const SMDS_MeshNode* n = nodes[0];
8992 for(j=0; j<nbFaceNodes-1; j++) {
8993 nodes[j] = nodes[j+1];
8995 nodes[nbFaceNodes-1] = n;
8997 il1 = il1 - nbshift;
8998 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8999 // n0 n1 n2 n0 n1 n2
9000 // +-----+-----+ +-----+-----+
9009 // create new elements
9010 int aShapeId = FindShape( theFace );
9013 if(nbFaceNodes==6) { // quadratic triangle
9014 SMDS_MeshElement* newElem =
9015 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9016 myLastCreatedElems.Append(newElem);
9017 if ( aShapeId && newElem )
9018 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9019 if(theFace->IsMediumNode(nodes[il1])) {
9020 // create quadrangle
9021 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9022 myLastCreatedElems.Append(newElem);
9023 if ( aShapeId && newElem )
9024 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9030 // create quadrangle
9031 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9032 myLastCreatedElems.Append(newElem);
9033 if ( aShapeId && newElem )
9034 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9040 else { // nbFaceNodes==8 - quadratic quadrangle
9041 SMDS_MeshElement* newElem =
9042 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9043 myLastCreatedElems.Append(newElem);
9044 if ( aShapeId && newElem )
9045 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9046 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9047 myLastCreatedElems.Append(newElem);
9048 if ( aShapeId && newElem )
9049 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9050 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9051 myLastCreatedElems.Append(newElem);
9052 if ( aShapeId && newElem )
9053 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9054 if(theFace->IsMediumNode(nodes[il1])) {
9055 // create quadrangle
9056 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9057 myLastCreatedElems.Append(newElem);
9058 if ( aShapeId && newElem )
9059 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9065 // create quadrangle
9066 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9067 myLastCreatedElems.Append(newElem);
9068 if ( aShapeId && newElem )
9069 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9075 // create needed triangles using n1,n2,n3 and inserted nodes
9076 int nbn = 2 + aNodesToInsert.size();
9077 //const SMDS_MeshNode* aNodes[nbn];
9078 vector<const SMDS_MeshNode*> aNodes(nbn);
9079 aNodes[0] = nodes[n1];
9080 aNodes[nbn-1] = nodes[n2];
9081 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9082 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9083 aNodes[iNode++] = *nIt;
9085 for(i=1; i<nbn; i++) {
9086 SMDS_MeshElement* newElem =
9087 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9088 myLastCreatedElems.Append(newElem);
9089 if ( aShapeId && newElem )
9090 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9094 aMesh->RemoveElement(theFace);
9097 //=======================================================================
9098 //function : UpdateVolumes
9100 //=======================================================================
9101 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9102 const SMDS_MeshNode* theBetweenNode2,
9103 list<const SMDS_MeshNode*>& theNodesToInsert)
9105 myLastCreatedElems.Clear();
9106 myLastCreatedNodes.Clear();
9108 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9109 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9110 const SMDS_MeshElement* elem = invElemIt->next();
9112 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9113 SMDS_VolumeTool aVolume (elem);
9114 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9117 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9118 int iface, nbFaces = aVolume.NbFaces();
9119 vector<const SMDS_MeshNode *> poly_nodes;
9120 vector<int> quantities (nbFaces);
9122 for (iface = 0; iface < nbFaces; iface++) {
9123 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9124 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9125 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9127 for (int inode = 0; inode < nbFaceNodes; inode++) {
9128 poly_nodes.push_back(faceNodes[inode]);
9130 if (nbInserted == 0) {
9131 if (faceNodes[inode] == theBetweenNode1) {
9132 if (faceNodes[inode + 1] == theBetweenNode2) {
9133 nbInserted = theNodesToInsert.size();
9135 // add nodes to insert
9136 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9137 for (; nIt != theNodesToInsert.end(); nIt++) {
9138 poly_nodes.push_back(*nIt);
9142 else if (faceNodes[inode] == theBetweenNode2) {
9143 if (faceNodes[inode + 1] == theBetweenNode1) {
9144 nbInserted = theNodesToInsert.size();
9146 // add nodes to insert in reversed order
9147 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9149 for (; nIt != theNodesToInsert.begin(); nIt--) {
9150 poly_nodes.push_back(*nIt);
9152 poly_nodes.push_back(*nIt);
9159 quantities[iface] = nbFaceNodes + nbInserted;
9162 // Replace or update the volume
9163 SMESHDS_Mesh *aMesh = GetMeshDS();
9165 if (elem->IsPoly()) {
9166 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9170 int aShapeId = FindShape( elem );
9172 SMDS_MeshElement* newElem =
9173 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9174 myLastCreatedElems.Append(newElem);
9175 if (aShapeId && newElem)
9176 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9178 aMesh->RemoveElement(elem);
9183 //=======================================================================
9185 * \brief Convert elements contained in a submesh to quadratic
9186 * \retval int - nb of checked elements
9188 //=======================================================================
9190 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9191 SMESH_MesherHelper& theHelper,
9192 const bool theForce3d)
9195 if( !theSm ) return nbElem;
9197 vector<int> nbNodeInFaces;
9198 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9199 while(ElemItr->more())
9202 const SMDS_MeshElement* elem = ElemItr->next();
9203 if( !elem || elem->IsQuadratic() ) continue;
9205 int id = elem->GetID();
9206 //MESSAGE("elem " << id);
9207 id = 0; // get a free number for new elements
9208 int nbNodes = elem->NbNodes();
9209 SMDSAbs_ElementType aType = elem->GetType();
9211 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9212 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9213 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9215 const SMDS_MeshElement* NewElem = 0;
9221 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9229 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9232 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9235 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9240 case SMDSAbs_Volume :
9245 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9248 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9251 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9254 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9255 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9258 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9265 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9267 theSm->AddElement( NewElem );
9269 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9271 // if (!GetMeshDS()->isCompacted())
9272 // GetMeshDS()->compactMesh();
9276 //=======================================================================
9277 //function : ConvertToQuadratic
9279 //=======================================================================
9280 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9282 SMESHDS_Mesh* meshDS = GetMeshDS();
9284 SMESH_MesherHelper aHelper(*myMesh);
9285 aHelper.SetIsQuadratic( true );
9287 int nbCheckedElems = 0;
9288 if ( myMesh->HasShapeToMesh() )
9290 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9292 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9293 while ( smIt->more() ) {
9294 SMESH_subMesh* sm = smIt->next();
9295 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9296 aHelper.SetSubShape( sm->GetSubShape() );
9297 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9302 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9303 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9305 SMESHDS_SubMesh *smDS = 0;
9306 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9307 while(aEdgeItr->more())
9309 const SMDS_MeshEdge* edge = aEdgeItr->next();
9310 if(edge && !edge->IsQuadratic())
9312 int id = edge->GetID();
9313 //MESSAGE("edge->GetID() " << id);
9314 const SMDS_MeshNode* n1 = edge->GetNode(0);
9315 const SMDS_MeshNode* n2 = edge->GetNode(1);
9317 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9319 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9320 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9323 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9324 while(aFaceItr->more())
9326 const SMDS_MeshFace* face = aFaceItr->next();
9327 if(!face || face->IsQuadratic() ) continue;
9329 int id = face->GetID();
9330 int nbNodes = face->NbNodes();
9331 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9333 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9335 SMDS_MeshFace * NewFace = 0;
9339 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9342 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9345 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9347 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9349 vector<int> nbNodeInFaces;
9350 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9351 while(aVolumeItr->more())
9353 const SMDS_MeshVolume* volume = aVolumeItr->next();
9354 if(!volume || volume->IsQuadratic() ) continue;
9356 int id = volume->GetID();
9357 int nbNodes = volume->NbNodes();
9358 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9359 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9360 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9362 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9364 SMDS_MeshVolume * NewVolume = 0;
9368 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9369 nodes[3], id, theForce3d );
9372 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9373 nodes[3], nodes[4], id, theForce3d);
9376 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9377 nodes[3], nodes[4], nodes[5], id, theForce3d);
9380 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9381 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9384 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9386 ReplaceElemInGroups(volume, NewVolume, meshDS);
9390 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9391 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9392 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9393 aHelper.FixQuadraticElements();
9395 if (!GetMeshDS()->isCompacted())
9396 GetMeshDS()->compactMesh();
9399 //=======================================================================
9401 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9402 * \retval int - nb of checked elements
9404 //=======================================================================
9406 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9407 SMDS_ElemIteratorPtr theItr,
9408 const int theShapeID)
9411 SMESHDS_Mesh* meshDS = GetMeshDS();
9412 const bool notFromGroups = false;
9414 while( theItr->more() )
9416 const SMDS_MeshElement* elem = theItr->next();
9418 if( elem && elem->IsQuadratic())
9420 int id = elem->GetID();
9421 int nbNodes = elem->NbNodes();
9422 vector<const SMDS_MeshNode *> nodes, mediumNodes;
9423 nodes.reserve( nbNodes );
9424 mediumNodes.reserve( nbNodes );
9426 for(int i = 0; i < nbNodes; i++)
9428 const SMDS_MeshNode* n = elem->GetNode(i);
9430 if( elem->IsMediumNode( n ) )
9431 mediumNodes.push_back( n );
9433 nodes.push_back( n );
9435 if( nodes.empty() ) continue;
9436 SMDSAbs_ElementType aType = elem->GetType();
9438 //remove old quadratic element
9439 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9441 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9442 ReplaceElemInGroups(elem, NewElem, meshDS);
9443 if( theSm && NewElem )
9444 theSm->AddElement( NewElem );
9446 // remove medium nodes
9447 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9448 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9449 const SMDS_MeshNode* n = *nIt;
9450 if ( n->NbInverseElements() == 0 ) {
9451 if ( n->getshapeId() != theShapeID )
9452 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9453 ( n->getshapeId() ));
9455 meshDS->RemoveFreeNode( n, theSm );
9463 //=======================================================================
9464 //function : ConvertFromQuadratic
9466 //=======================================================================
9467 bool SMESH_MeshEditor::ConvertFromQuadratic()
9469 int nbCheckedElems = 0;
9470 if ( myMesh->HasShapeToMesh() )
9472 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9474 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9475 while ( smIt->more() ) {
9476 SMESH_subMesh* sm = smIt->next();
9477 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9478 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9484 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9485 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9487 SMESHDS_SubMesh *aSM = 0;
9488 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9494 //=======================================================================
9495 //function : SewSideElements
9497 //=======================================================================
9499 SMESH_MeshEditor::Sew_Error
9500 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9501 TIDSortedElemSet& theSide2,
9502 const SMDS_MeshNode* theFirstNode1,
9503 const SMDS_MeshNode* theFirstNode2,
9504 const SMDS_MeshNode* theSecondNode1,
9505 const SMDS_MeshNode* theSecondNode2)
9507 myLastCreatedElems.Clear();
9508 myLastCreatedNodes.Clear();
9510 MESSAGE ("::::SewSideElements()");
9511 if ( theSide1.size() != theSide2.size() )
9512 return SEW_DIFF_NB_OF_ELEMENTS;
9514 Sew_Error aResult = SEW_OK;
9516 // 1. Build set of faces representing each side
9517 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9518 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9520 // =======================================================================
9521 // 1. Build set of faces representing each side:
9522 // =======================================================================
9523 // a. build set of nodes belonging to faces
9524 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9525 // c. create temporary faces representing side of volumes if correspondent
9526 // face does not exist
9528 SMESHDS_Mesh* aMesh = GetMeshDS();
9529 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9530 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9531 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9532 set<const SMDS_MeshElement*> volSet1, volSet2;
9533 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9534 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9535 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9536 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9537 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9538 int iSide, iFace, iNode;
9540 list<const SMDS_MeshElement* > tempFaceList;
9541 for ( iSide = 0; iSide < 2; iSide++ ) {
9542 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9543 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9544 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9545 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9546 set<const SMDS_MeshElement*>::iterator vIt;
9547 TIDSortedElemSet::iterator eIt;
9548 set<const SMDS_MeshNode*>::iterator nIt;
9550 // check that given nodes belong to given elements
9551 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9552 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9553 int firstIndex = -1, secondIndex = -1;
9554 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9555 const SMDS_MeshElement* elem = *eIt;
9556 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9557 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9558 if ( firstIndex > -1 && secondIndex > -1 ) break;
9560 if ( firstIndex < 0 || secondIndex < 0 ) {
9561 // we can simply return until temporary faces created
9562 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9565 // -----------------------------------------------------------
9566 // 1a. Collect nodes of existing faces
9567 // and build set of face nodes in order to detect missing
9568 // faces corresponding to sides of volumes
9569 // -----------------------------------------------------------
9571 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9573 // loop on the given element of a side
9574 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9575 //const SMDS_MeshElement* elem = *eIt;
9576 const SMDS_MeshElement* elem = *eIt;
9577 if ( elem->GetType() == SMDSAbs_Face ) {
9578 faceSet->insert( elem );
9579 set <const SMDS_MeshNode*> faceNodeSet;
9580 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9581 while ( nodeIt->more() ) {
9582 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9583 nodeSet->insert( n );
9584 faceNodeSet.insert( n );
9586 setOfFaceNodeSet.insert( faceNodeSet );
9588 else if ( elem->GetType() == SMDSAbs_Volume )
9589 volSet->insert( elem );
9591 // ------------------------------------------------------------------------------
9592 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9593 // ------------------------------------------------------------------------------
9595 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9596 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9597 while ( fIt->more() ) { // loop on faces sharing a node
9598 const SMDS_MeshElement* f = fIt->next();
9599 if ( faceSet->find( f ) == faceSet->end() ) {
9600 // check if all nodes are in nodeSet and
9601 // complete setOfFaceNodeSet if they are
9602 set <const SMDS_MeshNode*> faceNodeSet;
9603 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9604 bool allInSet = true;
9605 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9606 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9607 if ( nodeSet->find( n ) == nodeSet->end() )
9610 faceNodeSet.insert( n );
9613 faceSet->insert( f );
9614 setOfFaceNodeSet.insert( faceNodeSet );
9620 // -------------------------------------------------------------------------
9621 // 1c. Create temporary faces representing sides of volumes if correspondent
9622 // face does not exist
9623 // -------------------------------------------------------------------------
9625 if ( !volSet->empty() ) {
9626 //int nodeSetSize = nodeSet->size();
9628 // loop on given volumes
9629 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9630 SMDS_VolumeTool vol (*vIt);
9631 // loop on volume faces: find free faces
9632 // --------------------------------------
9633 list<const SMDS_MeshElement* > freeFaceList;
9634 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9635 if ( !vol.IsFreeFace( iFace ))
9637 // check if there is already a face with same nodes in a face set
9638 const SMDS_MeshElement* aFreeFace = 0;
9639 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9640 int nbNodes = vol.NbFaceNodes( iFace );
9641 set <const SMDS_MeshNode*> faceNodeSet;
9642 vol.GetFaceNodes( iFace, faceNodeSet );
9643 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9645 // no such a face is given but it still can exist, check it
9646 if ( nbNodes == 3 ) {
9647 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9649 else if ( nbNodes == 4 ) {
9650 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9653 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9654 aFreeFace = aMesh->FindFace(poly_nodes);
9658 // create a temporary face
9659 if ( nbNodes == 3 ) {
9660 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9661 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9663 else if ( nbNodes == 4 ) {
9664 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9665 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9668 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9669 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9670 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9674 freeFaceList.push_back( aFreeFace );
9675 tempFaceList.push_back( aFreeFace );
9678 } // loop on faces of a volume
9680 // choose one of several free faces
9681 // --------------------------------------
9682 if ( freeFaceList.size() > 1 ) {
9683 // choose a face having max nb of nodes shared by other elems of a side
9684 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9685 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9686 while ( fIt != freeFaceList.end() ) { // loop on free faces
9687 int nbSharedNodes = 0;
9688 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9689 while ( nodeIt->more() ) { // loop on free face nodes
9690 const SMDS_MeshNode* n =
9691 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9692 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9693 while ( invElemIt->more() ) {
9694 const SMDS_MeshElement* e = invElemIt->next();
9695 if ( faceSet->find( e ) != faceSet->end() )
9697 if ( elemSet->find( e ) != elemSet->end() )
9701 if ( nbSharedNodes >= maxNbNodes ) {
9702 maxNbNodes = nbSharedNodes;
9706 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9708 if ( freeFaceList.size() > 1 )
9710 // could not choose one face, use another way
9711 // choose a face most close to the bary center of the opposite side
9712 gp_XYZ aBC( 0., 0., 0. );
9713 set <const SMDS_MeshNode*> addedNodes;
9714 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9715 eIt = elemSet2->begin();
9716 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9717 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9718 while ( nodeIt->more() ) { // loop on free face nodes
9719 const SMDS_MeshNode* n =
9720 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9721 if ( addedNodes.insert( n ).second )
9722 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9725 aBC /= addedNodes.size();
9726 double minDist = DBL_MAX;
9727 fIt = freeFaceList.begin();
9728 while ( fIt != freeFaceList.end() ) { // loop on free faces
9730 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9731 while ( nodeIt->more() ) { // loop on free face nodes
9732 const SMDS_MeshNode* n =
9733 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9734 gp_XYZ p( n->X(),n->Y(),n->Z() );
9735 dist += ( aBC - p ).SquareModulus();
9737 if ( dist < minDist ) {
9739 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9742 fIt = freeFaceList.erase( fIt++ );
9745 } // choose one of several free faces of a volume
9747 if ( freeFaceList.size() == 1 ) {
9748 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9749 faceSet->insert( aFreeFace );
9750 // complete a node set with nodes of a found free face
9751 // for ( iNode = 0; iNode < ; iNode++ )
9752 // nodeSet->insert( fNodes[ iNode ] );
9755 } // loop on volumes of a side
9757 // // complete a set of faces if new nodes in a nodeSet appeared
9758 // // ----------------------------------------------------------
9759 // if ( nodeSetSize != nodeSet->size() ) {
9760 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9761 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9762 // while ( fIt->more() ) { // loop on faces sharing a node
9763 // const SMDS_MeshElement* f = fIt->next();
9764 // if ( faceSet->find( f ) == faceSet->end() ) {
9765 // // check if all nodes are in nodeSet and
9766 // // complete setOfFaceNodeSet if they are
9767 // set <const SMDS_MeshNode*> faceNodeSet;
9768 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9769 // bool allInSet = true;
9770 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9771 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9772 // if ( nodeSet->find( n ) == nodeSet->end() )
9773 // allInSet = false;
9775 // faceNodeSet.insert( n );
9777 // if ( allInSet ) {
9778 // faceSet->insert( f );
9779 // setOfFaceNodeSet.insert( faceNodeSet );
9785 } // Create temporary faces, if there are volumes given
9788 if ( faceSet1.size() != faceSet2.size() ) {
9789 // delete temporary faces: they are in reverseElements of actual nodes
9790 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9791 // while ( tmpFaceIt->more() )
9792 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9793 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9794 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9795 // aMesh->RemoveElement(*tmpFaceIt);
9796 MESSAGE("Diff nb of faces");
9797 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9800 // ============================================================
9801 // 2. Find nodes to merge:
9802 // bind a node to remove to a node to put instead
9803 // ============================================================
9805 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9806 if ( theFirstNode1 != theFirstNode2 )
9807 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9808 if ( theSecondNode1 != theSecondNode2 )
9809 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9811 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9812 set< long > linkIdSet; // links to process
9813 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9815 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9816 list< NLink > linkList[2];
9817 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9818 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9819 // loop on links in linkList; find faces by links and append links
9820 // of the found faces to linkList
9821 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9822 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9823 NLink link[] = { *linkIt[0], *linkIt[1] };
9824 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9825 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9828 // by links, find faces in the face sets,
9829 // and find indices of link nodes in the found faces;
9830 // in a face set, there is only one or no face sharing a link
9831 // ---------------------------------------------------------------
9833 const SMDS_MeshElement* face[] = { 0, 0 };
9834 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9835 vector<const SMDS_MeshNode*> fnodes1(9);
9836 vector<const SMDS_MeshNode*> fnodes2(9);
9837 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9838 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9839 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9840 int iLinkNode[2][2];
9841 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9842 const SMDS_MeshNode* n1 = link[iSide].first;
9843 const SMDS_MeshNode* n2 = link[iSide].second;
9844 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9845 set< const SMDS_MeshElement* > fMap;
9846 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9847 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9848 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9849 while ( fIt->more() ) { // loop on faces sharing a node
9850 const SMDS_MeshElement* f = fIt->next();
9851 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9852 ! fMap.insert( f ).second ) // f encounters twice
9854 if ( face[ iSide ] ) {
9855 MESSAGE( "2 faces per link " );
9856 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9860 faceSet->erase( f );
9861 // get face nodes and find ones of a link
9866 fnodes1.resize(f->NbNodes()+1);
9867 notLinkNodes1.resize(f->NbNodes()-2);
9870 fnodes2.resize(f->NbNodes()+1);
9871 notLinkNodes2.resize(f->NbNodes()-2);
9874 if(!f->IsQuadratic()) {
9875 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9876 while ( nIt->more() ) {
9877 const SMDS_MeshNode* n =
9878 static_cast<const SMDS_MeshNode*>( nIt->next() );
9880 iLinkNode[ iSide ][ 0 ] = iNode;
9882 else if ( n == n2 ) {
9883 iLinkNode[ iSide ][ 1 ] = iNode;
9885 //else if ( notLinkNodes[ iSide ][ 0 ] )
9886 // notLinkNodes[ iSide ][ 1 ] = n;
9888 // notLinkNodes[ iSide ][ 0 ] = n;
9892 notLinkNodes1[nbl] = n;
9893 //notLinkNodes1.push_back(n);
9895 notLinkNodes2[nbl] = n;
9896 //notLinkNodes2.push_back(n);
9898 //faceNodes[ iSide ][ iNode++ ] = n;
9900 fnodes1[iNode++] = n;
9903 fnodes2[iNode++] = n;
9907 else { // f->IsQuadratic()
9908 const SMDS_VtkFace* F =
9909 dynamic_cast<const SMDS_VtkFace*>(f);
9910 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9911 // use special nodes iterator
9912 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9913 while ( anIter->more() ) {
9914 const SMDS_MeshNode* n =
9915 static_cast<const SMDS_MeshNode*>( anIter->next() );
9917 iLinkNode[ iSide ][ 0 ] = iNode;
9919 else if ( n == n2 ) {
9920 iLinkNode[ iSide ][ 1 ] = iNode;
9925 notLinkNodes1[nbl] = n;
9928 notLinkNodes2[nbl] = n;
9932 fnodes1[iNode++] = n;
9935 fnodes2[iNode++] = n;
9939 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9941 fnodes1[iNode] = fnodes1[0];
9944 fnodes2[iNode] = fnodes1[0];
9951 // check similarity of elements of the sides
9952 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9953 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9954 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9955 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9958 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9960 break; // do not return because it s necessary to remove tmp faces
9963 // set nodes to merge
9964 // -------------------
9966 if ( face[0] && face[1] ) {
9967 int nbNodes = face[0]->NbNodes();
9968 if ( nbNodes != face[1]->NbNodes() ) {
9969 MESSAGE("Diff nb of face nodes");
9970 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9971 break; // do not return because it s necessary to remove tmp faces
9973 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9974 if ( nbNodes == 3 ) {
9975 //nReplaceMap.insert( TNodeNodeMap::value_type
9976 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9977 nReplaceMap.insert( TNodeNodeMap::value_type
9978 ( notLinkNodes1[0], notLinkNodes2[0] ));
9981 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9982 // analyse link orientation in faces
9983 int i1 = iLinkNode[ iSide ][ 0 ];
9984 int i2 = iLinkNode[ iSide ][ 1 ];
9985 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9986 // if notLinkNodes are the first and the last ones, then
9987 // their order does not correspond to the link orientation
9988 if (( i1 == 1 && i2 == 2 ) ||
9989 ( i1 == 2 && i2 == 1 ))
9990 reverse[ iSide ] = !reverse[ iSide ];
9992 if ( reverse[0] == reverse[1] ) {
9993 //nReplaceMap.insert( TNodeNodeMap::value_type
9994 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9995 //nReplaceMap.insert( TNodeNodeMap::value_type
9996 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9997 for(int nn=0; nn<nbNodes-2; nn++) {
9998 nReplaceMap.insert( TNodeNodeMap::value_type
9999 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10003 //nReplaceMap.insert( TNodeNodeMap::value_type
10004 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10005 //nReplaceMap.insert( TNodeNodeMap::value_type
10006 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10007 for(int nn=0; nn<nbNodes-2; nn++) {
10008 nReplaceMap.insert( TNodeNodeMap::value_type
10009 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10014 // add other links of the faces to linkList
10015 // -----------------------------------------
10017 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10018 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10019 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10020 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10021 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10022 if ( !iter_isnew.second ) { // already in a set: no need to process
10023 linkIdSet.erase( iter_isnew.first );
10025 else // new in set == encountered for the first time: add
10027 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10028 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10029 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10030 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10031 linkList[0].push_back ( NLink( n1, n2 ));
10032 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10036 } // loop on link lists
10038 if ( aResult == SEW_OK &&
10039 ( linkIt[0] != linkList[0].end() ||
10040 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10041 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10042 " " << (faceSetPtr[1]->empty()));
10043 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10046 // ====================================================================
10047 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10048 // ====================================================================
10050 // delete temporary faces: they are in reverseElements of actual nodes
10051 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10052 // while ( tmpFaceIt->more() )
10053 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10054 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10055 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10056 // aMesh->RemoveElement(*tmpFaceIt);
10058 if ( aResult != SEW_OK)
10061 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10062 // loop on nodes replacement map
10063 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10064 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10065 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10066 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10067 nodeIDsToRemove.push_back( nToRemove->GetID() );
10068 // loop on elements sharing nToRemove
10069 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10070 while ( invElemIt->more() ) {
10071 const SMDS_MeshElement* e = invElemIt->next();
10072 // get a new suite of nodes: make replacement
10073 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10074 vector< const SMDS_MeshNode*> nodes( nbNodes );
10075 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10076 while ( nIt->more() ) {
10077 const SMDS_MeshNode* n =
10078 static_cast<const SMDS_MeshNode*>( nIt->next() );
10079 nnIt = nReplaceMap.find( n );
10080 if ( nnIt != nReplaceMap.end() ) {
10082 n = (*nnIt).second;
10086 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10087 // elemIDsToRemove.push_back( e->GetID() );
10091 SMDSAbs_ElementType etyp = e->GetType();
10092 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10095 myLastCreatedElems.Append(newElem);
10096 AddToSameGroups(newElem, e, aMesh);
10097 int aShapeId = e->getshapeId();
10100 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10103 aMesh->RemoveElement(e);
10108 Remove( nodeIDsToRemove, true );
10113 //================================================================================
10115 * \brief Find corresponding nodes in two sets of faces
10116 * \param theSide1 - first face set
10117 * \param theSide2 - second first face
10118 * \param theFirstNode1 - a boundary node of set 1
10119 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10120 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10121 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10122 * \param nReplaceMap - output map of corresponding nodes
10123 * \retval bool - is a success or not
10125 //================================================================================
10128 //#define DEBUG_MATCHING_NODES
10131 SMESH_MeshEditor::Sew_Error
10132 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10133 set<const SMDS_MeshElement*>& theSide2,
10134 const SMDS_MeshNode* theFirstNode1,
10135 const SMDS_MeshNode* theFirstNode2,
10136 const SMDS_MeshNode* theSecondNode1,
10137 const SMDS_MeshNode* theSecondNode2,
10138 TNodeNodeMap & nReplaceMap)
10140 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10142 nReplaceMap.clear();
10143 if ( theFirstNode1 != theFirstNode2 )
10144 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10145 if ( theSecondNode1 != theSecondNode2 )
10146 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10148 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10149 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10151 list< NLink > linkList[2];
10152 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10153 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10155 // loop on links in linkList; find faces by links and append links
10156 // of the found faces to linkList
10157 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10158 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10159 NLink link[] = { *linkIt[0], *linkIt[1] };
10160 if ( linkSet.find( link[0] ) == linkSet.end() )
10163 // by links, find faces in the face sets,
10164 // and find indices of link nodes in the found faces;
10165 // in a face set, there is only one or no face sharing a link
10166 // ---------------------------------------------------------------
10168 const SMDS_MeshElement* face[] = { 0, 0 };
10169 list<const SMDS_MeshNode*> notLinkNodes[2];
10170 //bool reverse[] = { false, false }; // order of notLinkNodes
10172 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10174 const SMDS_MeshNode* n1 = link[iSide].first;
10175 const SMDS_MeshNode* n2 = link[iSide].second;
10176 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10177 set< const SMDS_MeshElement* > facesOfNode1;
10178 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10180 // during a loop of the first node, we find all faces around n1,
10181 // during a loop of the second node, we find one face sharing both n1 and n2
10182 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10183 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10184 while ( fIt->more() ) { // loop on faces sharing a node
10185 const SMDS_MeshElement* f = fIt->next();
10186 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10187 ! facesOfNode1.insert( f ).second ) // f encounters twice
10189 if ( face[ iSide ] ) {
10190 MESSAGE( "2 faces per link " );
10191 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10194 faceSet->erase( f );
10196 // get not link nodes
10197 int nbN = f->NbNodes();
10198 if ( f->IsQuadratic() )
10200 nbNodes[ iSide ] = nbN;
10201 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10202 int i1 = f->GetNodeIndex( n1 );
10203 int i2 = f->GetNodeIndex( n2 );
10204 int iEnd = nbN, iBeg = -1, iDelta = 1;
10205 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10207 std::swap( iEnd, iBeg ); iDelta = -1;
10212 if ( i == iEnd ) i = iBeg + iDelta;
10213 if ( i == i1 ) break;
10214 nodes.push_back ( f->GetNode( i ) );
10220 // check similarity of elements of the sides
10221 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10222 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10223 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10224 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10227 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10231 // set nodes to merge
10232 // -------------------
10234 if ( face[0] && face[1] ) {
10235 if ( nbNodes[0] != nbNodes[1] ) {
10236 MESSAGE("Diff nb of face nodes");
10237 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10239 #ifdef DEBUG_MATCHING_NODES
10240 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10241 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10242 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10244 int nbN = nbNodes[0];
10246 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10247 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10248 for ( int i = 0 ; i < nbN - 2; ++i ) {
10249 #ifdef DEBUG_MATCHING_NODES
10250 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10252 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10256 // add other links of the face 1 to linkList
10257 // -----------------------------------------
10259 const SMDS_MeshElement* f0 = face[0];
10260 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10261 for ( int i = 0; i < nbN; i++ )
10263 const SMDS_MeshNode* n2 = f0->GetNode( i );
10264 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10265 linkSet.insert( SMESH_TLink( n1, n2 ));
10266 if ( !iter_isnew.second ) { // already in a set: no need to process
10267 linkSet.erase( iter_isnew.first );
10269 else // new in set == encountered for the first time: add
10271 #ifdef DEBUG_MATCHING_NODES
10272 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10273 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10275 linkList[0].push_back ( NLink( n1, n2 ));
10276 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10281 } // loop on link lists
10286 //================================================================================
10288 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10289 \param theElems - the list of elements (edges or faces) to be replicated
10290 The nodes for duplication could be found from these elements
10291 \param theNodesNot - list of nodes to NOT replicate
10292 \param theAffectedElems - the list of elements (cells and edges) to which the
10293 replicated nodes should be associated to.
10294 \return TRUE if operation has been completed successfully, FALSE otherwise
10296 //================================================================================
10298 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10299 const TIDSortedElemSet& theNodesNot,
10300 const TIDSortedElemSet& theAffectedElems )
10302 myLastCreatedElems.Clear();
10303 myLastCreatedNodes.Clear();
10305 if ( theElems.size() == 0 )
10308 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10313 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10314 // duplicate elements and nodes
10315 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10316 // replce nodes by duplications
10317 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10321 //================================================================================
10323 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10324 \param theMeshDS - mesh instance
10325 \param theElems - the elements replicated or modified (nodes should be changed)
10326 \param theNodesNot - nodes to NOT replicate
10327 \param theNodeNodeMap - relation of old node to new created node
10328 \param theIsDoubleElem - flag os to replicate element or modify
10329 \return TRUE if operation has been completed successfully, FALSE otherwise
10331 //================================================================================
10333 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10334 const TIDSortedElemSet& theElems,
10335 const TIDSortedElemSet& theNodesNot,
10336 std::map< const SMDS_MeshNode*,
10337 const SMDS_MeshNode* >& theNodeNodeMap,
10338 const bool theIsDoubleElem )
10340 MESSAGE("doubleNodes");
10341 // iterate on through element and duplicate them (by nodes duplication)
10343 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10344 for ( ; elemItr != theElems.end(); ++elemItr )
10346 const SMDS_MeshElement* anElem = *elemItr;
10350 bool isDuplicate = false;
10351 // duplicate nodes to duplicate element
10352 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10353 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10355 while ( anIter->more() )
10358 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10359 SMDS_MeshNode* aNewNode = aCurrNode;
10360 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10361 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10362 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10365 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10366 theNodeNodeMap[ aCurrNode ] = aNewNode;
10367 myLastCreatedNodes.Append( aNewNode );
10369 isDuplicate |= (aCurrNode != aNewNode);
10370 newNodes[ ind++ ] = aNewNode;
10372 if ( !isDuplicate )
10375 if ( theIsDoubleElem )
10376 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10379 MESSAGE("ChangeElementNodes");
10380 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10387 //================================================================================
10389 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10390 \param theNodes - identifiers of nodes to be doubled
10391 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10392 nodes. If list of element identifiers is empty then nodes are doubled but
10393 they not assigned to elements
10394 \return TRUE if operation has been completed successfully, FALSE otherwise
10396 //================================================================================
10398 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10399 const std::list< int >& theListOfModifiedElems )
10401 MESSAGE("DoubleNodes");
10402 myLastCreatedElems.Clear();
10403 myLastCreatedNodes.Clear();
10405 if ( theListOfNodes.size() == 0 )
10408 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10412 // iterate through nodes and duplicate them
10414 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10416 std::list< int >::const_iterator aNodeIter;
10417 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10419 int aCurr = *aNodeIter;
10420 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10426 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10429 anOldNodeToNewNode[ aNode ] = aNewNode;
10430 myLastCreatedNodes.Append( aNewNode );
10434 // Create map of new nodes for modified elements
10436 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10438 std::list< int >::const_iterator anElemIter;
10439 for ( anElemIter = theListOfModifiedElems.begin();
10440 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10442 int aCurr = *anElemIter;
10443 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10447 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10449 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10451 while ( anIter->more() )
10453 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10454 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10456 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10457 aNodeArr[ ind++ ] = aNewNode;
10460 aNodeArr[ ind++ ] = aCurrNode;
10462 anElemToNodes[ anElem ] = aNodeArr;
10465 // Change nodes of elements
10467 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10468 anElemToNodesIter = anElemToNodes.begin();
10469 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10471 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10472 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10475 MESSAGE("ChangeElementNodes");
10476 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10485 //================================================================================
10487 \brief Check if element located inside shape
10488 \return TRUE if IN or ON shape, FALSE otherwise
10490 //================================================================================
10492 template<class Classifier>
10493 bool isInside(const SMDS_MeshElement* theElem,
10494 Classifier& theClassifier,
10495 const double theTol)
10497 gp_XYZ centerXYZ (0, 0, 0);
10498 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10499 while (aNodeItr->more())
10500 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10502 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10503 theClassifier.Perform(aPnt, theTol);
10504 TopAbs_State aState = theClassifier.State();
10505 return (aState == TopAbs_IN || aState == TopAbs_ON );
10508 //================================================================================
10510 * \brief Classifier of the 3D point on the TopoDS_Face
10511 * with interaface suitable for isInside()
10513 //================================================================================
10515 struct _FaceClassifier
10517 Extrema_ExtPS _extremum;
10518 BRepAdaptor_Surface _surface;
10519 TopAbs_State _state;
10521 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10523 _extremum.Initialize( _surface,
10524 _surface.FirstUParameter(), _surface.LastUParameter(),
10525 _surface.FirstVParameter(), _surface.LastVParameter(),
10526 _surface.Tolerance(), _surface.Tolerance() );
10528 void Perform(const gp_Pnt& aPnt, double theTol)
10530 _state = TopAbs_OUT;
10531 _extremum.Perform(aPnt);
10532 if ( _extremum.IsDone() )
10533 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10534 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10536 TopAbs_State State() const
10543 //================================================================================
10545 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10546 \param theElems - group of of elements (edges or faces) to be replicated
10547 \param theNodesNot - group of nodes not to replicate
10548 \param theShape - shape to detect affected elements (element which geometric center
10549 located on or inside shape).
10550 The replicated nodes should be associated to affected elements.
10551 \return TRUE if operation has been completed successfully, FALSE otherwise
10553 //================================================================================
10555 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10556 const TIDSortedElemSet& theNodesNot,
10557 const TopoDS_Shape& theShape )
10559 if ( theShape.IsNull() )
10562 const double aTol = Precision::Confusion();
10563 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10564 auto_ptr<_FaceClassifier> aFaceClassifier;
10565 if ( theShape.ShapeType() == TopAbs_SOLID )
10567 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10568 bsc3d->PerformInfinitePoint(aTol);
10570 else if (theShape.ShapeType() == TopAbs_FACE )
10572 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10575 // iterates on indicated elements and get elements by back references from their nodes
10576 TIDSortedElemSet anAffected;
10577 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10578 for ( ; elemItr != theElems.end(); ++elemItr )
10580 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10584 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10585 while ( nodeItr->more() )
10587 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10588 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10590 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10591 while ( backElemItr->more() )
10593 const SMDS_MeshElement* curElem = backElemItr->next();
10594 if ( curElem && theElems.find(curElem) == theElems.end() &&
10596 isInside( curElem, *bsc3d, aTol ) :
10597 isInside( curElem, *aFaceClassifier, aTol )))
10598 anAffected.insert( curElem );
10602 return DoubleNodes( theElems, theNodesNot, anAffected );
10606 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10607 * The list of groups must describe a partition of the mesh volumes.
10608 * The nodes of the internal faces at the boundaries of the groups are doubled.
10609 * In option, the internal faces are replaced by flat elements.
10610 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10611 * @param theElems - list of groups of volumes, where a group of volume is a set of
10612 * SMDS_MeshElements sorted by Id.
10613 * @param createJointElems - if TRUE, create the elements
10614 * @return TRUE if operation has been completed successfully, FALSE otherwise
10616 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10617 bool createJointElems)
10619 MESSAGE("----------------------------------------------");
10620 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10621 MESSAGE("----------------------------------------------");
10623 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10624 meshDS->BuildDownWardConnectivity(false);
10626 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10628 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10629 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10630 // build the list of nodes shared by 2 or more domains, with their domain indexes
10632 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10633 std::map<int,int>celldom; // cell vtkId --> domain
10634 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10635 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10636 faceDomains.clear();
10638 cellDomains.clear();
10639 nodeDomains.clear();
10640 std::map<int,int> emptyMap;
10643 for (int idom = 0; idom < theElems.size(); idom++)
10646 // --- build a map (face to duplicate --> volume to modify)
10647 // with all the faces shared by 2 domains (group of elements)
10648 // and corresponding volume of this domain, for each shared face.
10649 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10651 const TIDSortedElemSet& domain = theElems[idom];
10652 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10653 for (; elemItr != domain.end(); ++elemItr)
10655 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10658 int vtkId = anElem->getVtkId();
10659 int neighborsVtkIds[NBMAXNEIGHBORS];
10660 int downIds[NBMAXNEIGHBORS];
10661 unsigned char downTypes[NBMAXNEIGHBORS];
10662 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10663 for (int n = 0; n < nbNeighbors; n++)
10665 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10666 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10667 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10669 DownIdType face(downIds[n], downTypes[n]);
10670 if (!faceDomains.count(face))
10671 faceDomains[face] = emptyMap; // create an empty entry for face
10672 if (!faceDomains[face].count(idom))
10674 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10675 celldom[vtkId] = idom;
10682 MESSAGE("Number of shared faces " << faceDomains.size());
10683 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10685 // --- explore the shared faces domain by domain,
10686 // explore the nodes of the face and see if they belong to a cell in the domain,
10687 // which has only a node or an edge on the border (not a shared face)
10689 for (int idomain = 0; idomain < theElems.size(); idomain++)
10691 const TIDSortedElemSet& domain = theElems[idomain];
10692 itface = faceDomains.begin();
10693 for (; itface != faceDomains.end(); ++itface)
10695 std::map<int, int> domvol = itface->second;
10696 if (!domvol.count(idomain))
10698 DownIdType face = itface->first;
10699 //MESSAGE(" --- face " << face.cellId);
10700 std::set<int> oldNodes;
10702 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10703 std::set<int>::iterator itn = oldNodes.begin();
10704 for (; itn != oldNodes.end(); ++itn)
10707 //MESSAGE(" node " << oldId);
10708 std::set<int> cells;
10710 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10711 for (int i=0; i<l.ncells; i++)
10713 int vtkId = l.cells[i];
10714 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10715 if (!domain.count(anElem))
10717 int vtkType = grid->GetCellType(vtkId);
10718 int downId = grid->CellIdToDownId(vtkId);
10719 DownIdType aCell(downId, vtkType);
10720 if (celldom.count(vtkId))
10722 cellDomains[aCell][idomain] = vtkId;
10723 celldom[vtkId] = idomain;
10729 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10730 // for each shared face, get the nodes
10731 // for each node, for each domain of the face, create a clone of the node
10733 for (int idomain = 0; idomain < theElems.size(); idomain++)
10735 itface = faceDomains.begin();
10736 for (; itface != faceDomains.end(); ++itface)
10738 std::map<int, int> domvol = itface->second;
10739 if (!domvol.count(idomain))
10741 DownIdType face = itface->first;
10742 //MESSAGE(" --- face " << face.cellId);
10743 std::set<int> oldNodes;
10745 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10746 std::set<int>::iterator itn = oldNodes.begin();
10747 for (; itn != oldNodes.end(); ++itn)
10750 //MESSAGE(" node " << oldId);
10751 if (!nodeDomains.count(oldId))
10752 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10753 if (nodeDomains[oldId].empty())
10754 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10755 std::map<int, int>::iterator itdom = domvol.begin();
10756 for (; itdom != domvol.end(); ++itdom)
10758 int idom = itdom->first;
10759 //MESSAGE(" domain " << idom);
10760 if (!nodeDomains[oldId].count(idom))
10762 double *coords = grid->GetPoint(oldId);
10763 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10764 int newId = newNode->getVtkId();
10765 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10766 //MESSAGE(" newNode " << newId);
10773 // --- iterate on shared faces (volumes to modify, face to extrude)
10774 // get node id's of the face (id SMDS = id VTK)
10775 // create flat element with old and new nodes if requested
10777 if (createJointElems)
10779 itface = faceDomains.begin();
10780 for( ; itface != faceDomains.end();++itface )
10782 DownIdType face = itface->first;
10783 std::set<int> oldNodes;
10784 std::set<int>::iterator itn;
10786 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10788 std::map<int,int> domvol = itface->second;
10789 std::map<int,int>::iterator itdom = domvol.begin();
10790 int dom1 = itdom->first;
10791 int vtkVolId = itdom->second;
10793 int dom2 = itdom->first;
10794 meshDS->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains);
10798 // --- iterate on shared faces (volumes to modify, face to extrude)
10799 // get node id's of the face
10800 // replace old nodes by new nodes in volumes, and update inverse connectivity
10802 MESSAGE("cellDomains " << cellDomains.size());
10803 faceDomains.insert(cellDomains.begin(), cellDomains.end());
10804 itface = faceDomains.begin();
10805 for( ; itface != faceDomains.end();++itface )
10807 DownIdType face = itface->first;
10808 std::set<int> oldNodes;
10809 std::set<int>::iterator itn;
10811 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10812 std::map<int,int> localClonedNodeIds;
10814 std::map<int,int> domvol = itface->second;
10815 std::map<int,int>::iterator itdom = domvol.begin();
10816 for(; itdom != domvol.end(); ++itdom)
10818 int idom = itdom->first;
10819 int vtkVolId = itdom->second;
10820 localClonedNodeIds.clear();
10821 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10824 if (nodeDomains[oldId].count(idom))
10825 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10827 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10830 grid->BuildLinks();
10832 // TODO replace also old nodes by new nodes in faces and edges
10838 //================================================================================
10840 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10841 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10842 * \return TRUE if operation has been completed successfully, FALSE otherwise
10844 //================================================================================
10846 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10848 // iterates on volume elements and detect all free faces on them
10849 SMESHDS_Mesh* aMesh = GetMeshDS();
10852 //bool res = false;
10853 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10854 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10857 const SMDS_MeshVolume* volume = vIt->next();
10858 SMDS_VolumeTool vTool( volume );
10859 vTool.SetExternalNormal();
10860 const bool isPoly = volume->IsPoly();
10861 const bool isQuad = volume->IsQuadratic();
10862 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10864 if (!vTool.IsFreeFace(iface))
10867 vector<const SMDS_MeshNode *> nodes;
10868 int nbFaceNodes = vTool.NbFaceNodes(iface);
10869 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10871 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10872 nodes.push_back(faceNodes[inode]);
10874 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10875 nodes.push_back(faceNodes[inode]);
10877 // add new face based on volume nodes
10878 if (aMesh->FindFace( nodes ) ) {
10880 continue; // face already exsist
10882 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10886 return ( nbFree==(nbExisted+nbCreated) );
10891 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10893 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10895 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10898 //================================================================================
10900 * \brief Creates missing boundary elements
10901 * \param elements - elements whose boundary is to be checked
10902 * \param dimension - defines type of boundary elements to create
10903 * \param group - a group to store created boundary elements in
10904 * \param targetMesh - a mesh to store created boundary elements in
10905 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10906 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10907 * boundary elements will be copied into the targetMesh
10909 //================================================================================
10911 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10912 Bnd_Dimension dimension,
10913 SMESH_Group* group/*=0*/,
10914 SMESH_Mesh* targetMesh/*=0*/,
10915 bool toCopyElements/*=false*/,
10916 bool toCopyExistingBondary/*=false*/)
10918 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10919 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10920 // hope that all elements are of the same type, do not check them all
10921 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10922 throw SALOME_Exception(LOCALIZED("wrong element type"));
10925 toCopyElements = toCopyExistingBondary = false;
10927 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10928 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10930 SMDS_VolumeTool vTool;
10931 TIDSortedElemSet emptySet, avoidSet;
10934 typedef vector<const SMDS_MeshNode*> TConnectivity;
10936 SMDS_ElemIteratorPtr eIt;
10937 if (elements.empty())
10938 eIt = aMesh->elementsIterator(elemType);
10940 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10942 while (eIt->more())
10944 const SMDS_MeshElement* elem = eIt->next();
10945 const int iQuad = elem->IsQuadratic();
10947 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10948 vector<const SMDS_MeshElement*> presentBndElems;
10949 vector<TConnectivity> missingBndElems;
10950 TConnectivity nodes;
10951 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10953 vTool.SetExternalNormal();
10954 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10956 if (!vTool.IsFreeFace(iface))
10958 int nbFaceNodes = vTool.NbFaceNodes(iface);
10959 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10960 if ( missType == SMDSAbs_Edge ) // boundary edges
10962 nodes.resize( 2+iQuad );
10963 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10965 for ( int j = 0; j < nodes.size(); ++j )
10967 if ( const SMDS_MeshElement* edge =
10968 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10969 presentBndElems.push_back( edge );
10971 missingBndElems.push_back( nodes );
10974 else // boundary face
10977 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10978 nodes.push_back( nn[inode] );
10980 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10981 nodes.push_back( nn[inode] );
10983 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10984 presentBndElems.push_back( f );
10986 missingBndElems.push_back( nodes );
10990 else // elem is a face ------------------------------------------
10992 avoidSet.clear(), avoidSet.insert( elem );
10993 int nbNodes = elem->NbCornerNodes();
10994 nodes.resize( 2 /*+ iQuad*/);
10995 for ( int i = 0; i < nbNodes; i++ )
10997 nodes[0] = elem->GetNode(i);
10998 nodes[1] = elem->GetNode((i+1)%nbNodes);
10999 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
11000 continue; // not free link
11003 //nodes[2] = elem->GetNode( i + nbNodes );
11004 if ( const SMDS_MeshElement* edge =
11005 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11006 presentBndElems.push_back( edge );
11008 missingBndElems.push_back( nodes );
11012 // 2. Add missing boundary elements
11013 if ( targetMesh != myMesh )
11014 // instead of making a map of nodes in this mesh and targetMesh,
11015 // we create nodes with same IDs. We can renumber them later, if needed
11016 for ( int i = 0; i < missingBndElems.size(); ++i )
11018 TConnectivity& srcNodes = missingBndElems[i];
11019 TConnectivity nodes( srcNodes.size() );
11020 for ( inode = 0; inode < nodes.size(); ++inode )
11021 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11022 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11025 for ( int i = 0; i < missingBndElems.size(); ++i )
11027 TConnectivity& nodes = missingBndElems[i];
11028 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11031 // 3. Copy present boundary elements
11032 if ( toCopyExistingBondary )
11033 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11035 const SMDS_MeshElement* e = presentBndElems[i];
11036 TConnectivity nodes( e->NbNodes() );
11037 for ( inode = 0; inode < nodes.size(); ++inode )
11038 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11039 tgtEditor.AddElement(nodes, missType, e->IsPoly());
11040 // leave only missing elements in tgtEditor.myLastCreatedElems
11041 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
11043 } // loop on given elements
11045 // 4. Fill group with missing boundary elements
11048 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11049 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11050 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11052 tgtEditor.myLastCreatedElems.Clear();
11054 // 5. Copy given elements
11055 if ( toCopyElements )
11057 if (elements.empty())
11058 eIt = aMesh->elementsIterator(elemType);
11060 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11061 while (eIt->more())
11063 const SMDS_MeshElement* elem = eIt->next();
11064 TConnectivity nodes( elem->NbNodes() );
11065 for ( inode = 0; inode < nodes.size(); ++inode )
11066 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11067 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11069 tgtEditor.myLastCreatedElems.Clear();