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)
28 #include "SMESH_MeshEditor.hxx"
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_SetIterator.hxx"
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
50 #include "utilities.h"
52 #include <BRepAdaptor_Surface.hxx>
53 #include <BRepClass3d_SolidClassifier.hxx>
54 #include <BRep_Tool.hxx>
56 #include <Extrema_GenExtPS.hxx>
57 #include <Extrema_POnCurv.hxx>
58 #include <Extrema_POnSurf.hxx>
59 #include <GC_MakeSegment.hxx>
60 #include <Geom2d_Curve.hxx>
61 #include <GeomAPI_ExtremaCurveCurve.hxx>
62 #include <GeomAdaptor_Surface.hxx>
63 #include <Geom_Curve.hxx>
64 #include <Geom_Line.hxx>
65 #include <Geom_Surface.hxx>
66 #include <IntAna_IntConicQuad.hxx>
67 #include <IntAna_Quadric.hxx>
68 #include <Precision.hxx>
69 #include <TColStd_ListOfInteger.hxx>
70 #include <TopAbs_State.hxx>
72 #include <TopExp_Explorer.hxx>
73 #include <TopTools_ListIteratorOfListOfShape.hxx>
74 #include <TopTools_ListOfShape.hxx>
75 #include <TopTools_SequenceOfShape.hxx>
77 #include <TopoDS_Face.hxx>
83 #include <gp_Trsf.hxx>
95 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
98 using namespace SMESH::Controls;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
101 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
103 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
105 //=======================================================================
106 //function : SMESH_MeshEditor
108 //=======================================================================
110 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
111 :myMesh( theMesh ) // theMesh may be NULL
115 //=======================================================================
119 //=======================================================================
122 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
123 const SMDSAbs_ElementType type,
127 SMDS_MeshElement* e = 0;
128 int nbnode = node.size();
129 SMESHDS_Mesh* mesh = GetMeshDS();
131 case SMDSAbs_0DElement:
133 if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
134 else e = mesh->Add0DElement (node[0] );
138 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
139 else e = mesh->AddEdge (node[0], node[1] );
140 else if ( nbnode == 3 )
141 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
142 else e = mesh->AddEdge (node[0], node[1], node[2] );
147 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
148 else e = mesh->AddFace (node[0], node[1], node[2] );
149 else if (nbnode == 4)
150 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
151 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
152 else if (nbnode == 6)
153 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
154 node[4], node[5], ID);
155 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
157 else if (nbnode == 8)
158 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
159 node[4], node[5], node[6], node[7], ID);
160 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
161 node[4], node[5], node[6], node[7] );
163 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
164 else e = mesh->AddPolygonalFace (node );
170 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
171 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
172 else if (nbnode == 5)
173 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
177 else if (nbnode == 6)
178 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179 node[4], node[5], ID);
180 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
182 else if (nbnode == 8)
183 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
184 node[4], node[5], node[6], node[7], ID);
185 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
186 node[4], node[5], node[6], node[7] );
187 else if (nbnode == 10)
188 if ( ID ) 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],
194 else if (nbnode == 13)
195 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
196 node[4], node[5], node[6], node[7],
197 node[8], node[9], node[10],node[11],
199 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
200 node[4], node[5], node[6], node[7],
201 node[8], node[9], node[10],node[11],
203 else if (nbnode == 15)
204 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
205 node[4], node[5], node[6], node[7],
206 node[8], node[9], node[10],node[11],
207 node[12],node[13],node[14],ID);
208 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
209 node[4], node[5], node[6], node[7],
210 node[8], node[9], node[10],node[11],
211 node[12],node[13],node[14] );
212 else if (nbnode == 20)
213 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
214 node[4], node[5], node[6], node[7],
215 node[8], node[9], node[10],node[11],
216 node[12],node[13],node[14],node[15],
217 node[16],node[17],node[18],node[19],ID);
218 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
219 node[4], node[5], node[6], node[7],
220 node[8], node[9], node[10],node[11],
221 node[12],node[13],node[14],node[15],
222 node[16],node[17],node[18],node[19] );
225 if ( e ) myLastCreatedElems.Append( e );
229 //=======================================================================
233 //=======================================================================
235 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
236 const SMDSAbs_ElementType type,
240 vector<const SMDS_MeshNode*> nodes;
241 nodes.reserve( nodeIDs.size() );
242 vector<int>::const_iterator id = nodeIDs.begin();
243 while ( id != nodeIDs.end() ) {
244 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
245 nodes.push_back( node );
249 return AddElement( nodes, type, isPoly, ID );
252 //=======================================================================
254 //purpose : Remove a node or an element.
255 // Modify a compute state of sub-meshes which become empty
256 //=======================================================================
258 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
261 myLastCreatedElems.Clear();
262 myLastCreatedNodes.Clear();
264 SMESHDS_Mesh* aMesh = GetMeshDS();
265 set< SMESH_subMesh *> smmap;
268 list<int>::const_iterator it = theIDs.begin();
269 for ( ; it != theIDs.end(); it++ ) {
270 const SMDS_MeshElement * elem;
272 elem = aMesh->FindNode( *it );
274 elem = aMesh->FindElement( *it );
278 // Notify VERTEX sub-meshes about modification
280 const SMDS_MeshNode* node = cast2Node( elem );
281 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
282 if ( int aShapeID = node->GetPosition()->GetShapeId() )
283 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
286 // Find sub-meshes to notify about modification
287 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
288 // while ( nodeIt->more() ) {
289 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
290 // const SMDS_PositionPtr& aPosition = node->GetPosition();
291 // if ( aPosition.get() ) {
292 // if ( int aShapeID = aPosition->GetShapeId() ) {
293 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
294 // smmap.insert( sm );
301 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
303 aMesh->RemoveElement( elem );
307 // Notify sub-meshes about modification
308 if ( !smmap.empty() ) {
309 set< SMESH_subMesh *>::iterator smIt;
310 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
311 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
314 // // Check if the whole mesh becomes empty
315 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
316 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
321 //=======================================================================
322 //function : FindShape
323 //purpose : Return an index of the shape theElem is on
324 // or zero if a shape not found
325 //=======================================================================
327 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
329 myLastCreatedElems.Clear();
330 myLastCreatedNodes.Clear();
332 SMESHDS_Mesh * aMesh = GetMeshDS();
333 if ( aMesh->ShapeToMesh().IsNull() )
336 if ( theElem->GetType() == SMDSAbs_Node ) {
337 const SMDS_PositionPtr& aPosition =
338 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
339 if ( aPosition.get() )
340 return aPosition->GetShapeId();
345 TopoDS_Shape aShape; // the shape a node is on
346 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
347 while ( nodeIt->more() ) {
348 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
349 const SMDS_PositionPtr& aPosition = node->GetPosition();
350 if ( aPosition.get() ) {
351 int aShapeID = aPosition->GetShapeId();
352 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
354 if ( sm->Contains( theElem ))
356 if ( aShape.IsNull() )
357 aShape = aMesh->IndexToShape( aShapeID );
360 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
365 // None of nodes is on a proper shape,
366 // find the shape among ancestors of aShape on which a node is
367 if ( aShape.IsNull() ) {
368 //MESSAGE ("::FindShape() - NONE node is on shape")
371 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
372 for ( ; ancIt.More(); ancIt.Next() ) {
373 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
374 if ( sm && sm->Contains( theElem ))
375 return aMesh->ShapeToIndex( ancIt.Value() );
378 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
382 //=======================================================================
383 //function : IsMedium
385 //=======================================================================
387 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
388 const SMDSAbs_ElementType typeToCheck)
390 bool isMedium = false;
391 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
392 while (it->more() && !isMedium ) {
393 const SMDS_MeshElement* elem = it->next();
394 isMedium = elem->IsMediumNode(node);
399 //=======================================================================
400 //function : ShiftNodesQuadTria
402 // Shift nodes in the array corresponded to quadratic triangle
403 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
404 //=======================================================================
405 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
407 const SMDS_MeshNode* nd1 = aNodes[0];
408 aNodes[0] = aNodes[1];
409 aNodes[1] = aNodes[2];
411 const SMDS_MeshNode* nd2 = aNodes[3];
412 aNodes[3] = aNodes[4];
413 aNodes[4] = aNodes[5];
417 //=======================================================================
418 //function : GetNodesFromTwoTria
420 // Shift nodes in the array corresponded to quadratic triangle
421 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
422 //=======================================================================
423 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
424 const SMDS_MeshElement * theTria2,
425 const SMDS_MeshNode* N1[],
426 const SMDS_MeshNode* N2[])
428 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
431 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
434 if(it->more()) return false;
435 it = theTria2->nodesIterator();
438 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
441 if(it->more()) return false;
443 int sames[3] = {-1,-1,-1};
455 if(nbsames!=2) return false;
457 ShiftNodesQuadTria(N1);
459 ShiftNodesQuadTria(N1);
462 i = sames[0] + sames[1] + sames[2];
464 ShiftNodesQuadTria(N2);
466 // now we receive following N1 and N2 (using numeration as above image)
467 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
468 // i.e. first nodes from both arrays determ new diagonal
472 //=======================================================================
473 //function : InverseDiag
474 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
475 // but having other common link.
476 // Return False if args are improper
477 //=======================================================================
479 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
480 const SMDS_MeshElement * theTria2 )
482 myLastCreatedElems.Clear();
483 myLastCreatedNodes.Clear();
485 if (!theTria1 || !theTria2)
488 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
489 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
492 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
493 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
497 // put nodes in array and find out indices of the same ones
498 const SMDS_MeshNode* aNodes [6];
499 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
501 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
502 while ( it->more() ) {
503 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
505 if ( i > 2 ) // theTria2
506 // find same node of theTria1
507 for ( int j = 0; j < 3; j++ )
508 if ( aNodes[ i ] == aNodes[ j ]) {
517 return false; // theTria1 is not a triangle
518 it = theTria2->nodesIterator();
520 if ( i == 6 && it->more() )
521 return false; // theTria2 is not a triangle
524 // find indices of 1,2 and of A,B in theTria1
525 int iA = 0, iB = 0, i1 = 0, i2 = 0;
526 for ( i = 0; i < 6; i++ ) {
527 if ( sameInd [ i ] == 0 )
534 // nodes 1 and 2 should not be the same
535 if ( aNodes[ i1 ] == aNodes[ i2 ] )
539 aNodes[ iA ] = aNodes[ i2 ];
541 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
543 //MESSAGE( theTria1 << theTria2 );
545 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
546 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
548 //MESSAGE( theTria1 << theTria2 );
552 } // end if(F1 && F2)
554 // check case of quadratic faces
555 const SMDS_QuadraticFaceOfNodes* QF1 =
556 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
557 if(!QF1) return false;
558 const SMDS_QuadraticFaceOfNodes* QF2 =
559 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
560 if(!QF2) return false;
563 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
564 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
572 const SMDS_MeshNode* N1 [6];
573 const SMDS_MeshNode* N2 [6];
574 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
576 // now we receive following N1 and N2 (using numeration as above image)
577 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
578 // i.e. first nodes from both arrays determ new diagonal
580 const SMDS_MeshNode* N1new [6];
581 const SMDS_MeshNode* N2new [6];
594 // replaces nodes in faces
595 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
596 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
601 //=======================================================================
602 //function : findTriangles
603 //purpose : find triangles sharing theNode1-theNode2 link
604 //=======================================================================
606 static bool findTriangles(const SMDS_MeshNode * theNode1,
607 const SMDS_MeshNode * theNode2,
608 const SMDS_MeshElement*& theTria1,
609 const SMDS_MeshElement*& theTria2)
611 if ( !theNode1 || !theNode2 ) return false;
613 theTria1 = theTria2 = 0;
615 set< const SMDS_MeshElement* > emap;
616 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
618 const SMDS_MeshElement* elem = it->next();
619 if ( elem->NbNodes() == 3 )
622 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
624 const SMDS_MeshElement* elem = it->next();
625 if ( emap.find( elem ) != emap.end() )
627 // theTria1 must be element with minimum ID
628 if( theTria1->GetID() < elem->GetID() ) {
641 return ( theTria1 && theTria2 );
644 //=======================================================================
645 //function : InverseDiag
646 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
647 // with ones built on the same 4 nodes but having other common link.
648 // Return false if proper faces not found
649 //=======================================================================
651 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
652 const SMDS_MeshNode * theNode2)
654 myLastCreatedElems.Clear();
655 myLastCreatedNodes.Clear();
657 MESSAGE( "::InverseDiag()" );
659 const SMDS_MeshElement *tr1, *tr2;
660 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
663 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
664 //if (!F1) return false;
665 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
666 //if (!F2) return false;
669 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
670 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
674 // put nodes in array
675 // and find indices of 1,2 and of A in tr1 and of B in tr2
676 int i, iA1 = 0, i1 = 0;
677 const SMDS_MeshNode* aNodes1 [3];
678 SMDS_ElemIteratorPtr it;
679 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
680 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
681 if ( aNodes1[ i ] == theNode1 )
682 iA1 = i; // node A in tr1
683 else if ( aNodes1[ i ] != theNode2 )
687 const SMDS_MeshNode* aNodes2 [3];
688 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
689 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
690 if ( aNodes2[ i ] == theNode2 )
691 iB2 = i; // node B in tr2
692 else if ( aNodes2[ i ] != theNode1 )
696 // nodes 1 and 2 should not be the same
697 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
701 aNodes1[ iA1 ] = aNodes2[ i2 ];
703 aNodes2[ iB2 ] = aNodes1[ i1 ];
705 //MESSAGE( tr1 << tr2 );
707 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
708 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
710 //MESSAGE( tr1 << tr2 );
715 // check case of quadratic faces
716 const SMDS_QuadraticFaceOfNodes* QF1 =
717 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
718 if(!QF1) return false;
719 const SMDS_QuadraticFaceOfNodes* QF2 =
720 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
721 if(!QF2) return false;
722 return InverseDiag(tr1,tr2);
725 //=======================================================================
726 //function : getQuadrangleNodes
727 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
728 // fusion of triangles tr1 and tr2 having shared link on
729 // theNode1 and theNode2
730 //=======================================================================
732 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
733 const SMDS_MeshNode * theNode1,
734 const SMDS_MeshNode * theNode2,
735 const SMDS_MeshElement * tr1,
736 const SMDS_MeshElement * tr2 )
738 if( tr1->NbNodes() != tr2->NbNodes() )
740 // find the 4-th node to insert into tr1
741 const SMDS_MeshNode* n4 = 0;
742 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
744 while ( !n4 && i<3 ) {
745 const SMDS_MeshNode * n = cast2Node( it->next() );
747 bool isDiag = ( n == theNode1 || n == theNode2 );
751 // Make an array of nodes to be in a quadrangle
752 int iNode = 0, iFirstDiag = -1;
753 it = tr1->nodesIterator();
756 const SMDS_MeshNode * n = cast2Node( it->next() );
758 bool isDiag = ( n == theNode1 || n == theNode2 );
760 if ( iFirstDiag < 0 )
762 else if ( iNode - iFirstDiag == 1 )
763 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
765 else if ( n == n4 ) {
766 return false; // tr1 and tr2 should not have all the same nodes
768 theQuadNodes[ iNode++ ] = n;
770 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
771 theQuadNodes[ iNode ] = n4;
776 //=======================================================================
777 //function : DeleteDiag
778 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
779 // with a quadrangle built on the same 4 nodes.
780 // Return false if proper faces not found
781 //=======================================================================
783 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
784 const SMDS_MeshNode * theNode2)
786 myLastCreatedElems.Clear();
787 myLastCreatedNodes.Clear();
789 MESSAGE( "::DeleteDiag()" );
791 const SMDS_MeshElement *tr1, *tr2;
792 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
795 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
796 //if (!F1) return false;
797 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
798 //if (!F2) return false;
801 const SMDS_MeshNode* aNodes [ 4 ];
802 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
805 //MESSAGE( endl << tr1 << tr2 );
807 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
808 myLastCreatedElems.Append(tr1);
809 GetMeshDS()->RemoveElement( tr2 );
811 //MESSAGE( endl << tr1 );
816 // check case of quadratic faces
817 const SMDS_QuadraticFaceOfNodes* QF1 =
818 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
819 if(!QF1) return false;
820 const SMDS_QuadraticFaceOfNodes* QF2 =
821 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
822 if(!QF2) return false;
825 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
826 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
834 const SMDS_MeshNode* N1 [6];
835 const SMDS_MeshNode* N2 [6];
836 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
838 // now we receive following N1 and N2 (using numeration as above image)
839 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
840 // i.e. first nodes from both arrays determ new diagonal
842 const SMDS_MeshNode* aNodes[8];
852 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
853 myLastCreatedElems.Append(tr1);
854 GetMeshDS()->RemoveElement( tr2 );
856 // remove middle node (9)
857 GetMeshDS()->RemoveNode( N1[4] );
862 //=======================================================================
863 //function : Reorient
864 //purpose : Reverse theElement orientation
865 //=======================================================================
867 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
869 myLastCreatedElems.Clear();
870 myLastCreatedNodes.Clear();
874 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
875 if ( !it || !it->more() )
878 switch ( theElem->GetType() ) {
882 if(!theElem->IsQuadratic()) {
883 int i = theElem->NbNodes();
884 vector<const SMDS_MeshNode*> aNodes( i );
886 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
887 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
890 // quadratic elements
891 if(theElem->GetType()==SMDSAbs_Edge) {
892 vector<const SMDS_MeshNode*> aNodes(3);
893 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
894 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
895 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
896 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
899 int nbn = theElem->NbNodes();
900 vector<const SMDS_MeshNode*> aNodes(nbn);
901 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
903 for(; i<nbn/2; i++) {
904 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
906 for(i=0; i<nbn/2; i++) {
907 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
909 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
913 case SMDSAbs_Volume: {
914 if (theElem->IsPoly()) {
915 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
916 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
918 MESSAGE("Warning: bad volumic element");
922 int nbFaces = aPolyedre->NbFaces();
923 vector<const SMDS_MeshNode *> poly_nodes;
924 vector<int> quantities (nbFaces);
926 // reverse each face of the polyedre
927 for (int iface = 1; iface <= nbFaces; iface++) {
928 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
929 quantities[iface - 1] = nbFaceNodes;
931 for (inode = nbFaceNodes; inode >= 1; inode--) {
932 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
933 poly_nodes.push_back(curNode);
937 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
941 SMDS_VolumeTool vTool;
942 if ( !vTool.Set( theElem ))
945 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
954 //=======================================================================
955 //function : getBadRate
957 //=======================================================================
959 static double getBadRate (const SMDS_MeshElement* theElem,
960 SMESH::Controls::NumericalFunctorPtr& theCrit)
962 SMESH::Controls::TSequenceOfXYZ P;
963 if ( !theElem || !theCrit->GetPoints( theElem, P ))
965 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
966 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
969 //=======================================================================
970 //function : QuadToTri
971 //purpose : Cut quadrangles into triangles.
972 // theCrit is used to select a diagonal to cut
973 //=======================================================================
975 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
976 SMESH::Controls::NumericalFunctorPtr theCrit)
978 myLastCreatedElems.Clear();
979 myLastCreatedNodes.Clear();
981 MESSAGE( "::QuadToTri()" );
983 if ( !theCrit.get() )
986 SMESHDS_Mesh * aMesh = GetMeshDS();
988 Handle(Geom_Surface) surface;
989 SMESH_MesherHelper helper( *GetMesh() );
991 TIDSortedElemSet::iterator itElem;
992 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
993 const SMDS_MeshElement* elem = *itElem;
994 if ( !elem || elem->GetType() != SMDSAbs_Face )
996 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
999 // retrieve element nodes
1000 const SMDS_MeshNode* aNodes [8];
1001 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1003 while ( itN->more() )
1004 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1006 // compare two sets of possible triangles
1007 double aBadRate1, aBadRate2; // to what extent a set is bad
1008 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1009 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1010 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1012 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1013 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1014 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1016 int aShapeId = FindShape( elem );
1017 const SMDS_MeshElement* newElem = 0;
1019 if( !elem->IsQuadratic() ) {
1021 // split liner quadrangle
1023 if ( aBadRate1 <= aBadRate2 ) {
1024 // tr1 + tr2 is better
1025 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1026 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1029 // tr3 + tr4 is better
1030 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1031 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1036 // split quadratic quadrangle
1038 // get surface elem is on
1039 if ( aShapeId != helper.GetSubShapeID() ) {
1043 shape = aMesh->IndexToShape( aShapeId );
1044 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1045 TopoDS_Face face = TopoDS::Face( shape );
1046 surface = BRep_Tool::Surface( face );
1047 if ( !surface.IsNull() )
1048 helper.SetSubShape( shape );
1052 const SMDS_MeshNode* aNodes [8];
1053 const SMDS_MeshNode* inFaceNode = 0;
1054 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1056 while ( itN->more() ) {
1057 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1058 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1059 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1061 inFaceNode = aNodes[ i-1 ];
1064 // find middle point for (0,1,2,3)
1065 // and create a node in this point;
1067 if ( surface.IsNull() ) {
1069 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1073 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1076 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1078 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1080 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1081 myLastCreatedNodes.Append(newN);
1083 // create a new element
1084 const SMDS_MeshNode* N[6];
1085 if ( aBadRate1 <= aBadRate2 ) {
1092 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1093 aNodes[6], aNodes[7], newN );
1102 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1103 aNodes[7], aNodes[4], newN );
1105 aMesh->ChangeElementNodes( elem, N, 6 );
1109 // care of a new element
1111 myLastCreatedElems.Append(newElem);
1112 AddToSameGroups( newElem, elem, aMesh );
1114 // put a new triangle on the same shape
1116 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1121 //=======================================================================
1122 //function : BestSplit
1123 //purpose : Find better diagonal for cutting.
1124 //=======================================================================
1126 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1127 SMESH::Controls::NumericalFunctorPtr theCrit)
1129 myLastCreatedElems.Clear();
1130 myLastCreatedNodes.Clear();
1135 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1138 if( theQuad->NbNodes()==4 ||
1139 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1141 // retrieve element nodes
1142 const SMDS_MeshNode* aNodes [4];
1143 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1145 //while (itN->more())
1147 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1149 // compare two sets of possible triangles
1150 double aBadRate1, aBadRate2; // to what extent a set is bad
1151 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1152 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1153 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1155 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1156 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1157 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1159 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1160 return 1; // diagonal 1-3
1162 return 2; // diagonal 2-4
1169 // Methods of splitting volumes into tetra
1171 const int theHexTo5_1[5*4+1] =
1173 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1175 const int theHexTo5_2[5*4+1] =
1177 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1179 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1181 const int theHexTo6_1[6*4+1] =
1183 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
1185 const int theHexTo6_2[6*4+1] =
1187 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
1189 const int theHexTo6_3[6*4+1] =
1191 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
1193 const int theHexTo6_4[6*4+1] =
1195 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
1197 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1199 const int thePyraTo2_1[2*4+1] =
1201 0, 1, 2, 4, 0, 2, 3, 4, -1
1203 const int thePyraTo2_2[2*4+1] =
1205 1, 2, 3, 4, 1, 3, 0, 4, -1
1207 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1209 const int thePentaTo3_1[3*4+1] =
1211 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1213 const int thePentaTo3_2[3*4+1] =
1215 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1217 const int thePentaTo3_3[3*4+1] =
1219 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1221 const int thePentaTo3_4[3*4+1] =
1223 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1225 const int thePentaTo3_5[3*4+1] =
1227 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1229 const int thePentaTo3_6[3*4+1] =
1231 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1233 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1234 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1236 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1239 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1240 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1241 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1246 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1247 bool _baryNode; //!< additional node is to be created at cell barycenter
1248 bool _ownConn; //!< to delete _connectivity in destructor
1249 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1251 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1252 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1253 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1254 bool hasFacet( const TTriangleFacet& facet ) const
1256 const int* tetConn = _connectivity;
1257 for ( ; tetConn[0] >= 0; tetConn += 4 )
1258 if (( facet.contains( tetConn[0] ) +
1259 facet.contains( tetConn[1] ) +
1260 facet.contains( tetConn[2] ) +
1261 facet.contains( tetConn[3] )) == 3 )
1267 //=======================================================================
1269 * \brief return TSplitMethod for the given element
1271 //=======================================================================
1273 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1275 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1277 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1278 // an edge and a face barycenter; tertaherdons are based on triangles and
1279 // a volume barycenter
1280 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1282 // Find out how adjacent volumes are split
1284 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1285 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1286 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1288 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1289 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1290 if ( nbNodes < 4 ) continue;
1292 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1293 const int* nInd = vol.GetFaceNodesIndices( iF );
1296 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1297 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1298 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1299 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1303 int iCom = 0; // common node of triangle faces to split into
1304 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1306 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1307 nInd[ iQ * ( (iCom+1)%nbNodes )],
1308 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1309 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1310 nInd[ iQ * ( (iCom+2)%nbNodes )],
1311 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1312 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1314 triaSplits.push_back( t012 );
1315 triaSplits.push_back( t023 );
1320 if ( !triaSplits.empty() )
1321 hasAdjacentSplits = true;
1324 // Among variants of split method select one compliant with adjacent volumes
1326 TSplitMethod method;
1327 if ( !vol.Element()->IsPoly() && !is24TetMode )
1329 int nbVariants = 2, nbTet = 0;
1330 const int** connVariants = 0;
1331 switch ( vol.Element()->GetEntityType() )
1333 case SMDSEntity_Hexa:
1334 case SMDSEntity_Quad_Hexa:
1335 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1336 connVariants = theHexTo5, nbTet = 5;
1338 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1340 case SMDSEntity_Pyramid:
1341 case SMDSEntity_Quad_Pyramid:
1342 connVariants = thePyraTo2; nbTet = 2;
1344 case SMDSEntity_Penta:
1345 case SMDSEntity_Quad_Penta:
1346 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1351 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1353 // check method compliancy with adjacent tetras,
1354 // all found splits must be among facets of tetras described by this method
1355 method = TSplitMethod( nbTet, connVariants[variant] );
1356 if ( hasAdjacentSplits && method._nbTetra > 0 )
1358 bool facetCreated = true;
1359 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1361 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1362 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1363 facetCreated = method.hasFacet( *facet );
1365 if ( !facetCreated )
1366 method = TSplitMethod(0); // incompatible method
1370 if ( method._nbTetra < 1 )
1372 // No standard method is applicable, use a generic solution:
1373 // each facet of a volume is split into triangles and
1374 // each of triangles and a volume barycenter form a tetrahedron.
1376 int* connectivity = new int[ maxTetConnSize + 1 ];
1377 method._connectivity = connectivity;
1378 method._ownConn = true;
1379 method._baryNode = true;
1382 int baryCenInd = vol.NbNodes();
1383 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1385 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1386 const int* nInd = vol.GetFaceNodesIndices( iF );
1387 // find common node of triangle facets of tetra to create
1388 int iCommon = 0; // index in linear numeration
1389 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1390 if ( !triaSplits.empty() )
1393 const TTriangleFacet* facet = &triaSplits.front();
1394 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1395 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1396 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1399 else if ( nbNodes > 3 && !is24TetMode )
1401 // find the best method of splitting into triangles by aspect ratio
1402 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1403 map< double, int > badness2iCommon;
1404 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1405 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1406 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1407 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1409 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1410 nodes[ iQ*((iLast-1)%nbNodes)],
1411 nodes[ iQ*((iLast )%nbNodes)]);
1412 double badness = getBadRate( &tria, aspectRatio );
1413 badness2iCommon.insert( make_pair( badness, iCommon ));
1415 // use iCommon with lowest badness
1416 iCommon = badness2iCommon.begin()->second;
1418 if ( iCommon >= nbNodes )
1419 iCommon = 0; // something wrong
1421 // fill connectivity of tetrahedra based on a current face
1422 int nbTet = nbNodes - 2;
1423 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1425 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1426 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1428 for ( int i = 0; i < nbTet; ++i )
1430 int i1 = i, i2 = (i+1) % nbNodes;
1431 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1432 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1433 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1434 connectivity[ connSize++ ] = faceBaryCenInd;
1435 connectivity[ connSize++ ] = baryCenInd;
1440 for ( int i = 0; i < nbTet; ++i )
1442 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1443 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1444 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1445 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1446 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1447 connectivity[ connSize++ ] = baryCenInd;
1450 method._nbTetra += nbTet;
1452 connectivity[ connSize++ ] = -1;
1456 //================================================================================
1458 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1460 //================================================================================
1462 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1464 // find the tetrahedron including the three nodes of facet
1465 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1466 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1467 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1468 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1469 while ( volIt1->more() )
1471 const SMDS_MeshElement* v = volIt1->next();
1472 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1474 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1475 while ( volIt2->more() )
1476 if ( v != volIt2->next() )
1478 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1479 while ( volIt3->more() )
1480 if ( v == volIt3->next() )
1486 //=======================================================================
1488 * \brief A key of a face of volume
1490 //=======================================================================
1492 struct TVolumeFaceKey: pair< int, pair< int, int> >
1494 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1496 TIDSortedNodeSet sortedNodes;
1497 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1498 int nbNodes = vol.NbFaceNodes( iF );
1499 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1500 for ( int i = 0; i < nbNodes; i += iQ )
1501 sortedNodes.insert( fNodes[i] );
1502 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1503 first = (*(n++))->GetID();
1504 second.first = (*(n++))->GetID();
1505 second.second = (*(n++))->GetID();
1510 //=======================================================================
1511 //function : SplitVolumesIntoTetra
1512 //purpose : Split volumic elements into tetrahedra.
1513 //=======================================================================
1515 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1516 const int theMethodFlags)
1518 // std-like iterator on coordinates of nodes of mesh element
1519 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1520 NXyzIterator xyzEnd;
1522 SMDS_VolumeTool volTool;
1523 SMESH_MesherHelper helper( *GetMesh());
1525 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1526 SMESHDS_SubMesh* fSubMesh = subMesh;
1528 SMESH_SequenceOfElemPtr newNodes, newElems;
1530 // map face of volume to it's baricenrtic node
1531 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1534 TIDSortedElemSet::const_iterator elem = theElems.begin();
1535 for ( ; elem != theElems.end(); ++elem )
1537 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1538 if ( geomType <= SMDSEntity_Quad_Tetra )
1539 continue; // tetra or face or ...
1541 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1543 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1544 if ( splitMethod._nbTetra < 1 ) continue;
1546 // find submesh to add new tetras to
1547 if ( !subMesh || !subMesh->Contains( *elem ))
1549 int shapeID = FindShape( *elem );
1550 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1551 subMesh = GetMeshDS()->MeshElements( shapeID );
1554 if ( (*elem)->IsQuadratic() )
1557 // add quadratic links to the helper
1558 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1560 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1561 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1562 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1564 helper.SetIsQuadratic( true );
1569 helper.SetIsQuadratic( false );
1571 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1572 if ( splitMethod._baryNode )
1574 // make a node at barycenter
1575 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1576 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1577 nodes.push_back( gcNode );
1578 newNodes.Append( gcNode );
1580 if ( !splitMethod._faceBaryNode.empty() )
1582 // make or find baricentric nodes of faces
1583 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1584 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1586 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1587 volFace2BaryNode.insert
1588 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1591 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1592 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1594 nodes.push_back( iF_n->second = f_n->second );
1599 helper.SetElementsOnShape( true );
1600 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1601 const int* tetConn = splitMethod._connectivity;
1602 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1603 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1604 nodes[ tetConn[1] ],
1605 nodes[ tetConn[2] ],
1606 nodes[ tetConn[3] ]));
1608 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1610 // Split faces on sides of the split volume
1612 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1613 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1615 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1616 if ( nbNodes < 4 ) continue;
1618 // find an existing face
1619 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1620 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1621 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1624 helper.SetElementsOnShape( false );
1625 vector< const SMDS_MeshElement* > triangles;
1627 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1628 if ( iF_n != splitMethod._faceBaryNode.end() )
1630 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1632 const SMDS_MeshNode* n1 = fNodes[iN];
1633 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1634 const SMDS_MeshNode *n3 = iF_n->second;
1635 if ( !volTool.IsFaceExternal( iF ))
1637 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1642 // among possible triangles create ones discribed by split method
1643 const int* nInd = volTool.GetFaceNodesIndices( iF );
1644 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1645 int iCom = 0; // common node of triangle faces to split into
1646 list< TTriangleFacet > facets;
1647 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1649 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1650 nInd[ iQ * ( (iCom+1)%nbNodes )],
1651 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1652 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1653 nInd[ iQ * ( (iCom+2)%nbNodes )],
1654 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1655 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1657 facets.push_back( t012 );
1658 facets.push_back( t023 );
1659 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1660 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1661 nInd[ iQ * ((iLast-1)%nbNodes )],
1662 nInd[ iQ * ((iLast )%nbNodes )]));
1666 list< TTriangleFacet >::iterator facet = facets.begin();
1667 for ( ; facet != facets.end(); ++facet )
1669 if ( !volTool.IsFaceExternal( iF ))
1670 swap( facet->_n2, facet->_n3 );
1671 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1672 volNodes[ facet->_n2 ],
1673 volNodes[ facet->_n3 ]));
1676 // find submesh to add new triangles in
1677 if ( !fSubMesh || !fSubMesh->Contains( face ))
1679 int shapeID = FindShape( face );
1680 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1682 for ( int i = 0; i < triangles.size(); ++i )
1684 if ( !triangles.back() ) continue;
1686 fSubMesh->AddElement( triangles.back());
1687 newElems.Append( triangles.back() );
1689 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1690 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1693 } // loop on volume faces to split them into triangles
1695 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1697 } // loop on volumes to split
1699 myLastCreatedNodes = newNodes;
1700 myLastCreatedElems = newElems;
1703 //=======================================================================
1704 //function : AddToSameGroups
1705 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1706 //=======================================================================
1708 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1709 const SMDS_MeshElement* elemInGroups,
1710 SMESHDS_Mesh * aMesh)
1712 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1713 if (!groups.empty()) {
1714 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1715 for ( ; grIt != groups.end(); grIt++ ) {
1716 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1717 if ( group && group->Contains( elemInGroups ))
1718 group->SMDSGroup().Add( elemToAdd );
1724 //=======================================================================
1725 //function : RemoveElemFromGroups
1726 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1727 //=======================================================================
1728 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1729 SMESHDS_Mesh * aMesh)
1731 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1732 if (!groups.empty())
1734 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1735 for (; GrIt != groups.end(); GrIt++)
1737 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1738 if (!grp || grp->IsEmpty()) continue;
1739 grp->SMDSGroup().Remove(removeelem);
1744 //================================================================================
1746 * \brief Replace elemToRm by elemToAdd in the all groups
1748 //================================================================================
1750 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1751 const SMDS_MeshElement* elemToAdd,
1752 SMESHDS_Mesh * aMesh)
1754 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1755 if (!groups.empty()) {
1756 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1757 for ( ; grIt != groups.end(); grIt++ ) {
1758 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1759 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1760 group->SMDSGroup().Add( elemToAdd );
1765 //================================================================================
1767 * \brief Replace elemToRm by elemToAdd in the all groups
1769 //================================================================================
1771 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1772 const vector<const SMDS_MeshElement*>& elemToAdd,
1773 SMESHDS_Mesh * aMesh)
1775 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1776 if (!groups.empty())
1778 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1779 for ( ; grIt != groups.end(); grIt++ ) {
1780 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1781 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1782 for ( int i = 0; i < elemToAdd.size(); ++i )
1783 group->SMDSGroup().Add( elemToAdd[ i ] );
1788 //=======================================================================
1789 //function : QuadToTri
1790 //purpose : Cut quadrangles into triangles.
1791 // theCrit is used to select a diagonal to cut
1792 //=======================================================================
1794 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1795 const bool the13Diag)
1797 myLastCreatedElems.Clear();
1798 myLastCreatedNodes.Clear();
1800 MESSAGE( "::QuadToTri()" );
1802 SMESHDS_Mesh * aMesh = GetMeshDS();
1804 Handle(Geom_Surface) surface;
1805 SMESH_MesherHelper helper( *GetMesh() );
1807 TIDSortedElemSet::iterator itElem;
1808 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1809 const SMDS_MeshElement* elem = *itElem;
1810 if ( !elem || elem->GetType() != SMDSAbs_Face )
1812 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1813 if(!isquad) continue;
1815 if(elem->NbNodes()==4) {
1816 // retrieve element nodes
1817 const SMDS_MeshNode* aNodes [4];
1818 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1820 while ( itN->more() )
1821 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1823 int aShapeId = FindShape( elem );
1824 const SMDS_MeshElement* newElem = 0;
1826 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1827 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1830 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1831 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1833 myLastCreatedElems.Append(newElem);
1834 // put a new triangle on the same shape and add to the same groups
1836 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1837 AddToSameGroups( newElem, elem, aMesh );
1840 // Quadratic quadrangle
1842 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1844 // get surface elem is on
1845 int aShapeId = FindShape( elem );
1846 if ( aShapeId != helper.GetSubShapeID() ) {
1850 shape = aMesh->IndexToShape( aShapeId );
1851 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1852 TopoDS_Face face = TopoDS::Face( shape );
1853 surface = BRep_Tool::Surface( face );
1854 if ( !surface.IsNull() )
1855 helper.SetSubShape( shape );
1859 const SMDS_MeshNode* aNodes [8];
1860 const SMDS_MeshNode* inFaceNode = 0;
1861 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1863 while ( itN->more() ) {
1864 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1865 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1866 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1868 inFaceNode = aNodes[ i-1 ];
1872 // find middle point for (0,1,2,3)
1873 // and create a node in this point;
1875 if ( surface.IsNull() ) {
1877 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1881 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1884 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1886 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1888 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1889 myLastCreatedNodes.Append(newN);
1891 // create a new element
1892 const SMDS_MeshElement* newElem = 0;
1893 const SMDS_MeshNode* N[6];
1901 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1902 aNodes[6], aNodes[7], newN );
1911 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1912 aNodes[7], aNodes[4], newN );
1914 myLastCreatedElems.Append(newElem);
1915 aMesh->ChangeElementNodes( elem, N, 6 );
1916 // put a new triangle on the same shape and add to the same groups
1918 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1919 AddToSameGroups( newElem, elem, aMesh );
1926 //=======================================================================
1927 //function : getAngle
1929 //=======================================================================
1931 double getAngle(const SMDS_MeshElement * tr1,
1932 const SMDS_MeshElement * tr2,
1933 const SMDS_MeshNode * n1,
1934 const SMDS_MeshNode * n2)
1936 double angle = 2*PI; // bad angle
1939 SMESH::Controls::TSequenceOfXYZ P1, P2;
1940 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1941 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1944 if(!tr1->IsQuadratic())
1945 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1947 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1948 if ( N1.SquareMagnitude() <= gp::Resolution() )
1950 if(!tr2->IsQuadratic())
1951 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1953 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1954 if ( N2.SquareMagnitude() <= gp::Resolution() )
1957 // find the first diagonal node n1 in the triangles:
1958 // take in account a diagonal link orientation
1959 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1960 for ( int t = 0; t < 2; t++ ) {
1961 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1962 int i = 0, iDiag = -1;
1963 while ( it->more()) {
1964 const SMDS_MeshElement *n = it->next();
1965 if ( n == n1 || n == n2 )
1969 if ( i - iDiag == 1 )
1970 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1978 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1981 angle = N1.Angle( N2 );
1986 // =================================================
1987 // class generating a unique ID for a pair of nodes
1988 // and able to return nodes by that ID
1989 // =================================================
1993 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1994 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1997 long GetLinkID (const SMDS_MeshNode * n1,
1998 const SMDS_MeshNode * n2) const
2000 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2003 bool GetNodes (const long theLinkID,
2004 const SMDS_MeshNode* & theNode1,
2005 const SMDS_MeshNode* & theNode2) const
2007 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2008 if ( !theNode1 ) return false;
2009 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2010 if ( !theNode2 ) return false;
2016 const SMESHDS_Mesh* myMesh;
2021 //=======================================================================
2022 //function : TriToQuad
2023 //purpose : Fuse neighbour triangles into quadrangles.
2024 // theCrit is used to select a neighbour to fuse with.
2025 // theMaxAngle is a max angle between element normals at which
2026 // fusion is still performed.
2027 //=======================================================================
2029 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2030 SMESH::Controls::NumericalFunctorPtr theCrit,
2031 const double theMaxAngle)
2033 myLastCreatedElems.Clear();
2034 myLastCreatedNodes.Clear();
2036 MESSAGE( "::TriToQuad()" );
2038 if ( !theCrit.get() )
2041 SMESHDS_Mesh * aMesh = GetMeshDS();
2043 // Prepare data for algo: build
2044 // 1. map of elements with their linkIDs
2045 // 2. map of linkIDs with their elements
2047 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2048 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2049 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2050 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2052 TIDSortedElemSet::iterator itElem;
2053 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2054 const SMDS_MeshElement* elem = *itElem;
2055 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2056 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2057 if(!IsTria) continue;
2059 // retrieve element nodes
2060 const SMDS_MeshNode* aNodes [4];
2061 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2064 aNodes[ i++ ] = cast2Node( itN->next() );
2065 aNodes[ 3 ] = aNodes[ 0 ];
2068 for ( i = 0; i < 3; i++ ) {
2069 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2070 // check if elements sharing a link can be fused
2071 itLE = mapLi_listEl.find( link );
2072 if ( itLE != mapLi_listEl.end() ) {
2073 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2075 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2076 //if ( FindShape( elem ) != FindShape( elem2 ))
2077 // continue; // do not fuse triangles laying on different shapes
2078 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2079 continue; // avoid making badly shaped quads
2080 (*itLE).second.push_back( elem );
2083 mapLi_listEl[ link ].push_back( elem );
2085 mapEl_setLi [ elem ].insert( link );
2088 // Clean the maps from the links shared by a sole element, ie
2089 // links to which only one element is bound in mapLi_listEl
2091 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2092 int nbElems = (*itLE).second.size();
2093 if ( nbElems < 2 ) {
2094 const SMDS_MeshElement* elem = (*itLE).second.front();
2095 SMESH_TLink link = (*itLE).first;
2096 mapEl_setLi[ elem ].erase( link );
2097 if ( mapEl_setLi[ elem ].empty() )
2098 mapEl_setLi.erase( elem );
2102 // Algo: fuse triangles into quadrangles
2104 while ( ! mapEl_setLi.empty() ) {
2105 // Look for the start element:
2106 // the element having the least nb of shared links
2107 const SMDS_MeshElement* startElem = 0;
2109 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2110 int nbLinks = (*itEL).second.size();
2111 if ( nbLinks < minNbLinks ) {
2112 startElem = (*itEL).first;
2113 minNbLinks = nbLinks;
2114 if ( minNbLinks == 1 )
2119 // search elements to fuse starting from startElem or links of elements
2120 // fused earlyer - startLinks
2121 list< SMESH_TLink > startLinks;
2122 while ( startElem || !startLinks.empty() ) {
2123 while ( !startElem && !startLinks.empty() ) {
2124 // Get an element to start, by a link
2125 SMESH_TLink linkId = startLinks.front();
2126 startLinks.pop_front();
2127 itLE = mapLi_listEl.find( linkId );
2128 if ( itLE != mapLi_listEl.end() ) {
2129 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2130 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2131 for ( ; itE != listElem.end() ; itE++ )
2132 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2134 mapLi_listEl.erase( itLE );
2139 // Get candidates to be fused
2140 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2141 const SMESH_TLink *link12, *link13;
2143 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2144 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2145 ASSERT( !setLi.empty() );
2146 set< SMESH_TLink >::iterator itLi;
2147 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2149 const SMESH_TLink & link = (*itLi);
2150 itLE = mapLi_listEl.find( link );
2151 if ( itLE == mapLi_listEl.end() )
2154 const SMDS_MeshElement* elem = (*itLE).second.front();
2156 elem = (*itLE).second.back();
2157 mapLi_listEl.erase( itLE );
2158 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2169 // add other links of elem to list of links to re-start from
2170 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2171 set< SMESH_TLink >::iterator it;
2172 for ( it = links.begin(); it != links.end(); it++ ) {
2173 const SMESH_TLink& link2 = (*it);
2174 if ( link2 != link )
2175 startLinks.push_back( link2 );
2179 // Get nodes of possible quadrangles
2180 const SMDS_MeshNode *n12 [4], *n13 [4];
2181 bool Ok12 = false, Ok13 = false;
2182 const SMDS_MeshNode *linkNode1, *linkNode2;
2184 linkNode1 = link12->first;
2185 linkNode2 = link12->second;
2186 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2190 linkNode1 = link13->first;
2191 linkNode2 = link13->second;
2192 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2196 // Choose a pair to fuse
2197 if ( Ok12 && Ok13 ) {
2198 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2199 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2200 double aBadRate12 = getBadRate( &quad12, theCrit );
2201 double aBadRate13 = getBadRate( &quad13, theCrit );
2202 if ( aBadRate13 < aBadRate12 )
2209 // and remove fused elems and removed links from the maps
2210 mapEl_setLi.erase( tr1 );
2212 mapEl_setLi.erase( tr2 );
2213 mapLi_listEl.erase( *link12 );
2214 if(tr1->NbNodes()==3) {
2215 if( tr1->GetID() < tr2->GetID() ) {
2216 aMesh->ChangeElementNodes( tr1, n12, 4 );
2217 myLastCreatedElems.Append(tr1);
2218 aMesh->RemoveElement( tr2 );
2221 aMesh->ChangeElementNodes( tr2, n12, 4 );
2222 myLastCreatedElems.Append(tr2);
2223 aMesh->RemoveElement( tr1);
2227 const SMDS_MeshNode* N1 [6];
2228 const SMDS_MeshNode* N2 [6];
2229 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2230 // now we receive following N1 and N2 (using numeration as above image)
2231 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2232 // i.e. first nodes from both arrays determ new diagonal
2233 const SMDS_MeshNode* aNodes[8];
2242 if( tr1->GetID() < tr2->GetID() ) {
2243 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2244 myLastCreatedElems.Append(tr1);
2245 GetMeshDS()->RemoveElement( tr2 );
2248 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2249 myLastCreatedElems.Append(tr2);
2250 GetMeshDS()->RemoveElement( tr1 );
2252 // remove middle node (9)
2253 GetMeshDS()->RemoveNode( N1[4] );
2257 mapEl_setLi.erase( tr3 );
2258 mapLi_listEl.erase( *link13 );
2259 if(tr1->NbNodes()==3) {
2260 if( tr1->GetID() < tr2->GetID() ) {
2261 aMesh->ChangeElementNodes( tr1, n13, 4 );
2262 myLastCreatedElems.Append(tr1);
2263 aMesh->RemoveElement( tr3 );
2266 aMesh->ChangeElementNodes( tr3, n13, 4 );
2267 myLastCreatedElems.Append(tr3);
2268 aMesh->RemoveElement( tr1 );
2272 const SMDS_MeshNode* N1 [6];
2273 const SMDS_MeshNode* N2 [6];
2274 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2275 // now we receive following N1 and N2 (using numeration as above image)
2276 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2277 // i.e. first nodes from both arrays determ new diagonal
2278 const SMDS_MeshNode* aNodes[8];
2287 if( tr1->GetID() < tr2->GetID() ) {
2288 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2289 myLastCreatedElems.Append(tr1);
2290 GetMeshDS()->RemoveElement( tr3 );
2293 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2294 myLastCreatedElems.Append(tr3);
2295 GetMeshDS()->RemoveElement( tr1 );
2297 // remove middle node (9)
2298 GetMeshDS()->RemoveNode( N1[4] );
2302 // Next element to fuse: the rejected one
2304 startElem = Ok12 ? tr3 : tr2;
2306 } // if ( startElem )
2307 } // while ( startElem || !startLinks.empty() )
2308 } // while ( ! mapEl_setLi.empty() )
2314 /*#define DUMPSO(txt) \
2315 // cout << txt << endl;
2316 //=============================================================================
2320 //=============================================================================
2321 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2325 int tmp = idNodes[ i1 ];
2326 idNodes[ i1 ] = idNodes[ i2 ];
2327 idNodes[ i2 ] = tmp;
2328 gp_Pnt Ptmp = P[ i1 ];
2331 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2334 //=======================================================================
2335 //function : SortQuadNodes
2336 //purpose : Set 4 nodes of a quadrangle face in a good order.
2337 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2339 //=======================================================================
2341 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2346 for ( i = 0; i < 4; i++ ) {
2347 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2349 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2352 gp_Vec V1(P[0], P[1]);
2353 gp_Vec V2(P[0], P[2]);
2354 gp_Vec V3(P[0], P[3]);
2356 gp_Vec Cross1 = V1 ^ V2;
2357 gp_Vec Cross2 = V2 ^ V3;
2360 if (Cross1.Dot(Cross2) < 0)
2365 if (Cross1.Dot(Cross2) < 0)
2369 swap ( i, i + 1, idNodes, P );
2371 // for ( int ii = 0; ii < 4; ii++ ) {
2372 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2373 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2379 //=======================================================================
2380 //function : SortHexaNodes
2381 //purpose : Set 8 nodes of a hexahedron in a good order.
2382 // Return success status
2383 //=======================================================================
2385 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2390 DUMPSO( "INPUT: ========================================");
2391 for ( i = 0; i < 8; i++ ) {
2392 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2393 if ( !n ) return false;
2394 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2395 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2397 DUMPSO( "========================================");
2400 set<int> faceNodes; // ids of bottom face nodes, to be found
2401 set<int> checkedId1; // ids of tried 2-nd nodes
2402 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2403 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2404 int iMin, iLoop1 = 0;
2406 // Loop to try the 2-nd nodes
2408 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2410 // Find not checked 2-nd node
2411 for ( i = 1; i < 8; i++ )
2412 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2413 int id1 = idNodes[i];
2414 swap ( 1, i, idNodes, P );
2415 checkedId1.insert ( id1 );
2419 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2420 // ie that all but meybe one (id3 which is on the same face) nodes
2421 // lay on the same side from the triangle plane.
2423 bool manyInPlane = false; // more than 4 nodes lay in plane
2425 while ( ++iLoop2 < 6 ) {
2427 // get 1-2-3 plane coeffs
2428 Standard_Real A, B, C, D;
2429 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2430 if ( N.SquareMagnitude() > gp::Resolution() )
2432 gp_Pln pln ( P[0], N );
2433 pln.Coefficients( A, B, C, D );
2435 // find the node (iMin) closest to pln
2436 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2438 for ( i = 3; i < 8; i++ ) {
2439 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2440 if ( fabs( dist[i] ) < minDist ) {
2441 minDist = fabs( dist[i] );
2444 if ( fabs( dist[i] ) <= tol )
2445 idInPln.insert( idNodes[i] );
2448 // there should not be more than 4 nodes in bottom plane
2449 if ( idInPln.size() > 1 )
2451 DUMPSO( "### idInPln.size() = " << idInPln.size());
2452 // idInPlane does not contain the first 3 nodes
2453 if ( manyInPlane || idInPln.size() == 5)
2454 return false; // all nodes in one plane
2457 // set the 1-st node to be not in plane
2458 for ( i = 3; i < 8; i++ ) {
2459 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2460 DUMPSO( "### Reset 0-th node");
2461 swap( 0, i, idNodes, P );
2466 // reset to re-check second nodes
2467 leastDist = DBL_MAX;
2471 break; // from iLoop2;
2474 // check that the other 4 nodes are on the same side
2475 bool sameSide = true;
2476 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2477 for ( i = 3; sameSide && i < 8; i++ ) {
2479 sameSide = ( isNeg == dist[i] <= 0.);
2482 // keep best solution
2483 if ( sameSide && minDist < leastDist ) {
2484 leastDist = minDist;
2486 faceNodes.insert( idNodes[ 1 ] );
2487 faceNodes.insert( idNodes[ 2 ] );
2488 faceNodes.insert( idNodes[ iMin ] );
2489 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2490 << " leastDist = " << leastDist);
2491 if ( leastDist <= DBL_MIN )
2496 // set next 3-d node to check
2497 int iNext = 2 + iLoop2;
2499 DUMPSO( "Try 2-nd");
2500 swap ( 2, iNext, idNodes, P );
2502 } // while ( iLoop2 < 6 )
2505 if ( faceNodes.empty() ) return false;
2507 // Put the faceNodes in proper places
2508 for ( i = 4; i < 8; i++ ) {
2509 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2510 // find a place to put
2512 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2514 DUMPSO( "Set faceNodes");
2515 swap ( iTo, i, idNodes, P );
2520 // Set nodes of the found bottom face in good order
2521 DUMPSO( " Found bottom face: ");
2522 i = SortQuadNodes( theMesh, idNodes );
2524 gp_Pnt Ptmp = P[ i ];
2529 // for ( int ii = 0; ii < 4; ii++ ) {
2530 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2531 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2534 // Gravity center of the top and bottom faces
2535 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2536 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2538 // Get direction from the bottom to the top face
2539 gp_Vec upDir ( aGCb, aGCt );
2540 Standard_Real upDirSize = upDir.Magnitude();
2541 if ( upDirSize <= gp::Resolution() ) return false;
2544 // Assure that the bottom face normal points up
2545 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2546 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2547 if ( Nb.Dot( upDir ) < 0 ) {
2548 DUMPSO( "Reverse bottom face");
2549 swap( 1, 3, idNodes, P );
2552 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2553 Standard_Real minDist = DBL_MAX;
2554 for ( i = 4; i < 8; i++ ) {
2555 // projection of P[i] to the plane defined by P[0] and upDir
2556 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2557 Standard_Real sqDist = P[0].SquareDistance( Pp );
2558 if ( sqDist < minDist ) {
2563 DUMPSO( "Set 4-th");
2564 swap ( 4, iMin, idNodes, P );
2566 // Set nodes of the top face in good order
2567 DUMPSO( "Sort top face");
2568 i = SortQuadNodes( theMesh, &idNodes[4] );
2571 gp_Pnt Ptmp = P[ i ];
2576 // Assure that direction of the top face normal is from the bottom face
2577 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2578 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2579 if ( Nt.Dot( upDir ) < 0 ) {
2580 DUMPSO( "Reverse top face");
2581 swap( 5, 7, idNodes, P );
2584 // DUMPSO( "OUTPUT: ========================================");
2585 // for ( i = 0; i < 8; i++ ) {
2586 // float *p = ugrid->GetPoint(idNodes[i]);
2587 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2593 //================================================================================
2595 * \brief Return nodes linked to the given one
2596 * \param theNode - the node
2597 * \param linkedNodes - the found nodes
2598 * \param type - the type of elements to check
2600 * Medium nodes are ignored
2602 //================================================================================
2604 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2605 TIDSortedElemSet & linkedNodes,
2606 SMDSAbs_ElementType type )
2608 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2609 while ( elemIt->more() )
2611 const SMDS_MeshElement* elem = elemIt->next();
2612 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2613 if ( elem->GetType() == SMDSAbs_Volume )
2615 SMDS_VolumeTool vol( elem );
2616 while ( nodeIt->more() ) {
2617 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2618 if ( theNode != n && vol.IsLinked( theNode, n ))
2619 linkedNodes.insert( n );
2624 for ( int i = 0; nodeIt->more(); ++i ) {
2625 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2626 if ( n == theNode ) {
2627 int iBefore = i - 1;
2629 if ( elem->IsQuadratic() ) {
2630 int nb = elem->NbNodes() / 2;
2631 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2632 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2634 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2635 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2642 //=======================================================================
2643 //function : laplacianSmooth
2644 //purpose : pulls theNode toward the center of surrounding nodes directly
2645 // connected to that node along an element edge
2646 //=======================================================================
2648 void laplacianSmooth(const SMDS_MeshNode* theNode,
2649 const Handle(Geom_Surface)& theSurface,
2650 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2652 // find surrounding nodes
2654 TIDSortedElemSet nodeSet;
2655 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2657 // compute new coodrs
2659 double coord[] = { 0., 0., 0. };
2660 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2661 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2662 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2663 if ( theSurface.IsNull() ) { // smooth in 3D
2664 coord[0] += node->X();
2665 coord[1] += node->Y();
2666 coord[2] += node->Z();
2668 else { // smooth in 2D
2669 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2670 gp_XY* uv = theUVMap[ node ];
2671 coord[0] += uv->X();
2672 coord[1] += uv->Y();
2675 int nbNodes = nodeSet.size();
2678 coord[0] /= nbNodes;
2679 coord[1] /= nbNodes;
2681 if ( !theSurface.IsNull() ) {
2682 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2683 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2684 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2690 coord[2] /= nbNodes;
2694 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2697 //=======================================================================
2698 //function : centroidalSmooth
2699 //purpose : pulls theNode toward the element-area-weighted centroid of the
2700 // surrounding elements
2701 //=======================================================================
2703 void centroidalSmooth(const SMDS_MeshNode* theNode,
2704 const Handle(Geom_Surface)& theSurface,
2705 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2707 gp_XYZ aNewXYZ(0.,0.,0.);
2708 SMESH::Controls::Area anAreaFunc;
2709 double totalArea = 0.;
2714 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2715 while ( elemIt->more() )
2717 const SMDS_MeshElement* elem = elemIt->next();
2720 gp_XYZ elemCenter(0.,0.,0.);
2721 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2722 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2723 int nn = elem->NbNodes();
2724 if(elem->IsQuadratic()) nn = nn/2;
2726 //while ( itN->more() ) {
2728 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2730 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2731 aNodePoints.push_back( aP );
2732 if ( !theSurface.IsNull() ) { // smooth in 2D
2733 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2734 gp_XY* uv = theUVMap[ aNode ];
2735 aP.SetCoord( uv->X(), uv->Y(), 0. );
2739 double elemArea = anAreaFunc.GetValue( aNodePoints );
2740 totalArea += elemArea;
2742 aNewXYZ += elemCenter * elemArea;
2744 aNewXYZ /= totalArea;
2745 if ( !theSurface.IsNull() ) {
2746 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2747 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2752 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2755 //=======================================================================
2756 //function : getClosestUV
2757 //purpose : return UV of closest projection
2758 //=======================================================================
2760 static bool getClosestUV (Extrema_GenExtPS& projector,
2761 const gp_Pnt& point,
2764 projector.Perform( point );
2765 if ( projector.IsDone() ) {
2766 double u, v, minVal = DBL_MAX;
2767 for ( int i = projector.NbExt(); i > 0; i-- )
2768 if ( projector.Value( i ) < minVal ) {
2769 minVal = projector.Value( i );
2770 projector.Point( i ).Parameter( u, v );
2772 result.SetCoord( u, v );
2778 //=======================================================================
2780 //purpose : Smooth theElements during theNbIterations or until a worst
2781 // element has aspect ratio <= theTgtAspectRatio.
2782 // Aspect Ratio varies in range [1.0, inf].
2783 // If theElements is empty, the whole mesh is smoothed.
2784 // theFixedNodes contains additionally fixed nodes. Nodes built
2785 // on edges and boundary nodes are always fixed.
2786 //=======================================================================
2788 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2789 set<const SMDS_MeshNode*> & theFixedNodes,
2790 const SmoothMethod theSmoothMethod,
2791 const int theNbIterations,
2792 double theTgtAspectRatio,
2795 myLastCreatedElems.Clear();
2796 myLastCreatedNodes.Clear();
2798 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2800 if ( theTgtAspectRatio < 1.0 )
2801 theTgtAspectRatio = 1.0;
2803 const double disttol = 1.e-16;
2805 SMESH::Controls::AspectRatio aQualityFunc;
2807 SMESHDS_Mesh* aMesh = GetMeshDS();
2809 if ( theElems.empty() ) {
2810 // add all faces to theElems
2811 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2812 while ( fIt->more() ) {
2813 const SMDS_MeshElement* face = fIt->next();
2814 theElems.insert( face );
2817 // get all face ids theElems are on
2818 set< int > faceIdSet;
2819 TIDSortedElemSet::iterator itElem;
2821 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2822 int fId = FindShape( *itElem );
2823 // check that corresponding submesh exists and a shape is face
2825 faceIdSet.find( fId ) == faceIdSet.end() &&
2826 aMesh->MeshElements( fId )) {
2827 TopoDS_Shape F = aMesh->IndexToShape( fId );
2828 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2829 faceIdSet.insert( fId );
2832 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2834 // ===============================================
2835 // smooth elements on each TopoDS_Face separately
2836 // ===============================================
2838 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2839 for ( ; fId != faceIdSet.rend(); ++fId ) {
2840 // get face surface and submesh
2841 Handle(Geom_Surface) surface;
2842 SMESHDS_SubMesh* faceSubMesh = 0;
2844 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2845 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2846 bool isUPeriodic = false, isVPeriodic = false;
2848 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2849 surface = BRep_Tool::Surface( face );
2850 faceSubMesh = aMesh->MeshElements( *fId );
2851 fToler2 = BRep_Tool::Tolerance( face );
2852 fToler2 *= fToler2 * 10.;
2853 isUPeriodic = surface->IsUPeriodic();
2855 vPeriod = surface->UPeriod();
2856 isVPeriodic = surface->IsVPeriodic();
2858 uPeriod = surface->VPeriod();
2859 surface->Bounds( u1, u2, v1, v2 );
2861 // ---------------------------------------------------------
2862 // for elements on a face, find movable and fixed nodes and
2863 // compute UV for them
2864 // ---------------------------------------------------------
2865 bool checkBoundaryNodes = false;
2866 bool isQuadratic = false;
2867 set<const SMDS_MeshNode*> setMovableNodes;
2868 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2869 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2870 list< const SMDS_MeshElement* > elemsOnFace;
2872 Extrema_GenExtPS projector;
2873 GeomAdaptor_Surface surfAdaptor;
2874 if ( !surface.IsNull() ) {
2875 surfAdaptor.Load( surface );
2876 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2878 int nbElemOnFace = 0;
2879 itElem = theElems.begin();
2880 // loop on not yet smoothed elements: look for elems on a face
2881 while ( itElem != theElems.end() ) {
2882 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2883 break; // all elements found
2885 const SMDS_MeshElement* elem = *itElem;
2886 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2887 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2891 elemsOnFace.push_back( elem );
2892 theElems.erase( itElem++ );
2896 isQuadratic = elem->IsQuadratic();
2898 // get movable nodes of elem
2899 const SMDS_MeshNode* node;
2900 SMDS_TypeOfPosition posType;
2901 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2902 int nn = 0, nbn = elem->NbNodes();
2903 if(elem->IsQuadratic())
2905 while ( nn++ < nbn ) {
2906 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2907 const SMDS_PositionPtr& pos = node->GetPosition();
2908 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2909 if (posType != SMDS_TOP_EDGE &&
2910 posType != SMDS_TOP_VERTEX &&
2911 theFixedNodes.find( node ) == theFixedNodes.end())
2913 // check if all faces around the node are on faceSubMesh
2914 // because a node on edge may be bound to face
2915 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2917 if ( faceSubMesh ) {
2918 while ( eIt->more() && all ) {
2919 const SMDS_MeshElement* e = eIt->next();
2920 all = faceSubMesh->Contains( e );
2924 setMovableNodes.insert( node );
2926 checkBoundaryNodes = true;
2928 if ( posType == SMDS_TOP_3DSPACE )
2929 checkBoundaryNodes = true;
2932 if ( surface.IsNull() )
2935 // get nodes to check UV
2936 list< const SMDS_MeshNode* > uvCheckNodes;
2937 itN = elem->nodesIterator();
2938 nn = 0; nbn = elem->NbNodes();
2939 if(elem->IsQuadratic())
2941 while ( nn++ < nbn ) {
2942 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2943 if ( uvMap.find( node ) == uvMap.end() )
2944 uvCheckNodes.push_back( node );
2945 // add nodes of elems sharing node
2946 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2947 // while ( eIt->more() ) {
2948 // const SMDS_MeshElement* e = eIt->next();
2949 // if ( e != elem ) {
2950 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2951 // while ( nIt->more() ) {
2952 // const SMDS_MeshNode* n =
2953 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2954 // if ( uvMap.find( n ) == uvMap.end() )
2955 // uvCheckNodes.push_back( n );
2961 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2962 for ( ; n != uvCheckNodes.end(); ++n ) {
2965 const SMDS_PositionPtr& pos = node->GetPosition();
2966 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2968 switch ( posType ) {
2969 case SMDS_TOP_FACE: {
2970 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2971 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2974 case SMDS_TOP_EDGE: {
2975 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2976 Handle(Geom2d_Curve) pcurve;
2977 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2978 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2979 if ( !pcurve.IsNull() ) {
2980 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2981 uv = pcurve->Value( u ).XY();
2985 case SMDS_TOP_VERTEX: {
2986 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2987 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2988 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2993 // check existing UV
2994 bool project = true;
2995 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2996 double dist1 = DBL_MAX, dist2 = 0;
2997 if ( posType != SMDS_TOP_3DSPACE ) {
2998 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2999 project = dist1 > fToler2;
3001 if ( project ) { // compute new UV
3003 if ( !getClosestUV( projector, pNode, newUV )) {
3004 MESSAGE("Node Projection Failed " << node);
3008 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3010 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3012 if ( posType != SMDS_TOP_3DSPACE )
3013 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3014 if ( dist2 < dist1 )
3018 // store UV in the map
3019 listUV.push_back( uv );
3020 uvMap.insert( make_pair( node, &listUV.back() ));
3022 } // loop on not yet smoothed elements
3024 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3025 checkBoundaryNodes = true;
3027 // fix nodes on mesh boundary
3029 if ( checkBoundaryNodes ) {
3030 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3031 map< NLink, int >::iterator link_nb;
3032 // put all elements links to linkNbMap
3033 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3034 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3035 const SMDS_MeshElement* elem = (*elemIt);
3036 int nbn = elem->NbNodes();
3037 if(elem->IsQuadratic())
3039 // loop on elem links: insert them in linkNbMap
3040 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3041 for ( int iN = 0; iN < nbn; ++iN ) {
3042 curNode = elem->GetNode( iN );
3044 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3045 else link = make_pair( prevNode , curNode );
3047 link_nb = linkNbMap.find( link );
3048 if ( link_nb == linkNbMap.end() )
3049 linkNbMap.insert( make_pair ( link, 1 ));
3054 // remove nodes that are in links encountered only once from setMovableNodes
3055 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3056 if ( link_nb->second == 1 ) {
3057 setMovableNodes.erase( link_nb->first.first );
3058 setMovableNodes.erase( link_nb->first.second );
3063 // -----------------------------------------------------
3064 // for nodes on seam edge, compute one more UV ( uvMap2 );
3065 // find movable nodes linked to nodes on seam and which
3066 // are to be smoothed using the second UV ( uvMap2 )
3067 // -----------------------------------------------------
3069 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3070 if ( !surface.IsNull() ) {
3071 TopExp_Explorer eExp( face, TopAbs_EDGE );
3072 for ( ; eExp.More(); eExp.Next() ) {
3073 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3074 if ( !BRep_Tool::IsClosed( edge, face ))
3076 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3077 if ( !sm ) continue;
3078 // find out which parameter varies for a node on seam
3081 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3082 if ( pcurve.IsNull() ) continue;
3083 uv1 = pcurve->Value( f );
3085 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3086 if ( pcurve.IsNull() ) continue;
3087 uv2 = pcurve->Value( f );
3088 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3090 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3091 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3093 // get nodes on seam and its vertices
3094 list< const SMDS_MeshNode* > seamNodes;
3095 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3096 while ( nSeamIt->more() ) {
3097 const SMDS_MeshNode* node = nSeamIt->next();
3098 if ( !isQuadratic || !IsMedium( node ))
3099 seamNodes.push_back( node );
3101 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3102 for ( ; vExp.More(); vExp.Next() ) {
3103 sm = aMesh->MeshElements( vExp.Current() );
3105 nSeamIt = sm->GetNodes();
3106 while ( nSeamIt->more() )
3107 seamNodes.push_back( nSeamIt->next() );
3110 // loop on nodes on seam
3111 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3112 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3113 const SMDS_MeshNode* nSeam = *noSeIt;
3114 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3115 if ( n_uv == uvMap.end() )
3118 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3119 // set the second UV
3120 listUV.push_back( *n_uv->second );
3121 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3122 if ( uvMap2.empty() )
3123 uvMap2 = uvMap; // copy the uvMap contents
3124 uvMap2[ nSeam ] = &listUV.back();
3126 // collect movable nodes linked to ones on seam in nodesNearSeam
3127 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3128 while ( eIt->more() ) {
3129 const SMDS_MeshElement* e = eIt->next();
3130 int nbUseMap1 = 0, nbUseMap2 = 0;
3131 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3132 int nn = 0, nbn = e->NbNodes();
3133 if(e->IsQuadratic()) nbn = nbn/2;
3134 while ( nn++ < nbn )
3136 const SMDS_MeshNode* n =
3137 static_cast<const SMDS_MeshNode*>( nIt->next() );
3139 setMovableNodes.find( n ) == setMovableNodes.end() )
3141 // add only nodes being closer to uv2 than to uv1
3142 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3143 0.5 * ( n->Y() + nSeam->Y() ),
3144 0.5 * ( n->Z() + nSeam->Z() ));
3146 getClosestUV( projector, pMid, uv );
3147 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3148 nodesNearSeam.insert( n );
3154 // for centroidalSmooth all element nodes must
3155 // be on one side of a seam
3156 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3157 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3159 while ( nn++ < nbn ) {
3160 const SMDS_MeshNode* n =
3161 static_cast<const SMDS_MeshNode*>( nIt->next() );
3162 setMovableNodes.erase( n );
3166 } // loop on nodes on seam
3167 } // loop on edge of a face
3168 } // if ( !face.IsNull() )
3170 if ( setMovableNodes.empty() ) {
3171 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3172 continue; // goto next face
3180 double maxRatio = -1., maxDisplacement = -1.;
3181 set<const SMDS_MeshNode*>::iterator nodeToMove;
3182 for ( it = 0; it < theNbIterations; it++ ) {
3183 maxDisplacement = 0.;
3184 nodeToMove = setMovableNodes.begin();
3185 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3186 const SMDS_MeshNode* node = (*nodeToMove);
3187 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3190 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3191 if ( theSmoothMethod == LAPLACIAN )
3192 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3194 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3196 // node displacement
3197 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3198 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3199 if ( aDispl > maxDisplacement )
3200 maxDisplacement = aDispl;
3202 // no node movement => exit
3203 //if ( maxDisplacement < 1.e-16 ) {
3204 if ( maxDisplacement < disttol ) {
3205 MESSAGE("-- no node movement --");
3209 // check elements quality
3211 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3212 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3213 const SMDS_MeshElement* elem = (*elemIt);
3214 if ( !elem || elem->GetType() != SMDSAbs_Face )
3216 SMESH::Controls::TSequenceOfXYZ aPoints;
3217 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3218 double aValue = aQualityFunc.GetValue( aPoints );
3219 if ( aValue > maxRatio )
3223 if ( maxRatio <= theTgtAspectRatio ) {
3224 MESSAGE("-- quality achived --");
3227 if (it+1 == theNbIterations) {
3228 MESSAGE("-- Iteration limit exceeded --");
3230 } // smoothing iterations
3232 MESSAGE(" Face id: " << *fId <<
3233 " Nb iterstions: " << it <<
3234 " Displacement: " << maxDisplacement <<
3235 " Aspect Ratio " << maxRatio);
3237 // ---------------------------------------
3238 // new nodes positions are computed,
3239 // record movement in DS and set new UV
3240 // ---------------------------------------
3241 nodeToMove = setMovableNodes.begin();
3242 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3243 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3244 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3245 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3246 if ( node_uv != uvMap.end() ) {
3247 gp_XY* uv = node_uv->second;
3249 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3253 // move medium nodes of quadratic elements
3256 SMESH_MesherHelper helper( *GetMesh() );
3257 if ( !face.IsNull() )
3258 helper.SetSubShape( face );
3259 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3260 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3261 const SMDS_QuadraticFaceOfNodes* QF =
3262 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3264 vector<const SMDS_MeshNode*> Ns;
3265 Ns.reserve(QF->NbNodes()+1);
3266 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3267 while ( anIter->more() )
3268 Ns.push_back( anIter->next() );
3269 Ns.push_back( Ns[0] );
3271 for(int i=0; i<QF->NbNodes(); i=i+2) {
3272 if ( !surface.IsNull() ) {
3273 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3274 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3275 gp_XY uv = ( uv1 + uv2 ) / 2.;
3276 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3277 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3280 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3281 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3282 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3284 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3285 fabs( Ns[i+1]->Y() - y ) > disttol ||
3286 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3287 // we have to move i+1 node
3288 aMesh->MoveNode( Ns[i+1], x, y, z );
3295 } // loop on face ids
3299 //=======================================================================
3300 //function : isReverse
3301 //purpose : Return true if normal of prevNodes is not co-directied with
3302 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3303 // iNotSame is where prevNodes and nextNodes are different
3304 //=======================================================================
3306 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3307 vector<const SMDS_MeshNode*> nextNodes,
3311 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3312 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3314 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3315 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3316 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3317 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3319 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3320 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3321 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3322 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3324 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3326 return (vA ^ vB) * vN < 0.0;
3329 //=======================================================================
3331 * \brief Create elements by sweeping an element
3332 * \param elem - element to sweep
3333 * \param newNodesItVec - nodes generated from each node of the element
3334 * \param newElems - generated elements
3335 * \param nbSteps - number of sweeping steps
3336 * \param srcElements - to append elem for each generated element
3338 //=======================================================================
3340 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3341 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3342 list<const SMDS_MeshElement*>& newElems,
3344 SMESH_SequenceOfElemPtr& srcElements)
3346 SMESHDS_Mesh* aMesh = GetMeshDS();
3348 // Loop on elem nodes:
3349 // find new nodes and detect same nodes indices
3350 int nbNodes = elem->NbNodes();
3351 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3352 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3353 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3354 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3356 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3357 vector<int> sames(nbNodes);
3358 vector<bool> issimple(nbNodes);
3360 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3361 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3362 const SMDS_MeshNode* node = nnIt->first;
3363 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3364 if ( listNewNodes.empty() ) {
3368 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3370 itNN[ iNode ] = listNewNodes.begin();
3371 prevNod[ iNode ] = node;
3372 nextNod[ iNode ] = listNewNodes.front();
3373 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3374 if ( prevNod[ iNode ] != nextNod [ iNode ])
3375 iNotSameNode = iNode;
3379 sames[nbSame++] = iNode;
3384 //cout<<" nbSame = "<<nbSame<<endl;
3385 if ( nbSame == nbNodes || nbSame > 2) {
3386 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3387 //INFOS( " Too many same nodes of element " << elem->GetID() );
3391 // if( elem->IsQuadratic() && nbSame>0 ) {
3392 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3396 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3397 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3399 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3400 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3401 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3405 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3406 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3407 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3408 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3410 // check element orientation
3412 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3413 //MESSAGE("Reversed elem " << elem );
3417 std::swap( iBeforeSame, iAfterSame );
3420 // make new elements
3421 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3423 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3424 if(issimple[iNode]) {
3425 nextNod[ iNode ] = *itNN[ iNode ];
3429 if( elem->GetType()==SMDSAbs_Node ) {
3430 // we have to use two nodes
3431 midlNod[ iNode ] = *itNN[ iNode ];
3433 nextNod[ iNode ] = *itNN[ iNode ];
3436 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3437 // we have to use each second node
3439 nextNod[ iNode ] = *itNN[ iNode ];
3443 // we have to use two nodes
3444 midlNod[ iNode ] = *itNN[ iNode ];
3446 nextNod[ iNode ] = *itNN[ iNode ];
3451 SMDS_MeshElement* aNewElem = 0;
3452 if(!elem->IsPoly()) {
3453 switch ( nbNodes ) {
3457 if ( nbSame == 0 ) {
3459 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3461 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3467 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3468 nextNod[ 1 ], nextNod[ 0 ] );
3470 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3471 nextNod[ iNotSameNode ] );
3475 case 3: { // TRIANGLE or quadratic edge
3476 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3478 if ( nbSame == 0 ) // --- pentahedron
3479 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3480 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3482 else if ( nbSame == 1 ) // --- pyramid
3483 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3484 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3485 nextNod[ iSameNode ]);
3487 else // 2 same nodes: --- tetrahedron
3488 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3489 nextNod[ iNotSameNode ]);
3491 else { // quadratic edge
3492 if(nbSame==0) { // quadratic quadrangle
3493 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3494 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3496 else if(nbSame==1) { // quadratic triangle
3498 return; // medium node on axis
3500 else if(sames[0]==0) {
3501 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3502 nextNod[2], midlNod[1], prevNod[2]);
3504 else { // sames[0]==1
3505 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3506 midlNod[0], nextNod[2], prevNod[2]);
3515 case 4: { // QUADRANGLE
3517 if ( nbSame == 0 ) // --- hexahedron
3518 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3519 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3521 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3522 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3523 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3524 nextNod[ iSameNode ]);
3525 newElems.push_back( aNewElem );
3526 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3527 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3528 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3530 else if ( nbSame == 2 ) { // pentahedron
3531 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3532 // iBeforeSame is same too
3533 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3534 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3535 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3537 // iAfterSame is same too
3538 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3539 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3540 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3544 case 6: { // quadratic triangle
3545 // create pentahedron with 15 nodes
3547 if(i0>0) { // reversed case
3548 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3549 nextNod[0], nextNod[2], nextNod[1],
3550 prevNod[5], prevNod[4], prevNod[3],
3551 nextNod[5], nextNod[4], nextNod[3],
3552 midlNod[0], midlNod[2], midlNod[1]);
3554 else { // not reversed case
3555 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3556 nextNod[0], nextNod[1], nextNod[2],
3557 prevNod[3], prevNod[4], prevNod[5],
3558 nextNod[3], nextNod[4], nextNod[5],
3559 midlNod[0], midlNod[1], midlNod[2]);
3562 else if(nbSame==1) {
3563 // 2d order pyramid of 13 nodes
3564 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3565 // int n12,int n23,int n34,int n41,
3566 // int n15,int n25,int n35,int n45, int ID);
3568 int n1,n4,n41,n15,n45;
3569 if(i0>0) { // reversed case
3570 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3571 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3577 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3578 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3583 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3584 nextNod[n4], prevNod[n4], prevNod[n5],
3585 midlNod[n1], nextNod[n41],
3586 midlNod[n4], prevNod[n41],
3587 prevNod[n15], nextNod[n15],
3588 nextNod[n45], prevNod[n45]);
3590 else if(nbSame==2) {
3591 // 2d order tetrahedron of 10 nodes
3592 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3593 // int n12,int n23,int n31,
3594 // int n14,int n24,int n34, int ID);
3595 int n1 = iNotSameNode;
3596 int n2,n3,n12,n23,n31;
3597 if(i0>0) { // reversed case
3598 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3599 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3605 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3606 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3611 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3612 prevNod[n12], prevNod[n23], prevNod[n31],
3613 midlNod[n1], nextNod[n12], nextNod[n31]);
3617 case 8: { // quadratic quadrangle
3619 // create hexahedron with 20 nodes
3620 if(i0>0) { // reversed case
3621 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3622 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3623 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3624 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3625 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3627 else { // not reversed case
3628 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3629 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3630 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3631 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3632 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3635 else if(nbSame==1) {
3636 // --- pyramid + pentahedron - can not be created since it is needed
3637 // additional middle node ot the center of face
3638 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3641 else if(nbSame==2) {
3642 // 2d order Pentahedron with 15 nodes
3643 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3644 // int n12,int n23,int n31,int n45,int n56,int n64,
3645 // int n14,int n25,int n36, int ID);
3647 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3648 // iBeforeSame is same too
3655 // iAfterSame is same too
3661 int n12,n45,n14,n25;
3662 if(i0>0) { //reversed case
3674 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3675 prevNod[n4], prevNod[n5], nextNod[n5],
3676 prevNod[n12], midlNod[n2], nextNod[n12],
3677 prevNod[n45], midlNod[n5], nextNod[n45],
3678 prevNod[n14], prevNod[n25], nextNod[n25]);
3683 // realized for extrusion only
3684 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3685 //vector<int> quantities (nbNodes + 2);
3687 //quantities[0] = nbNodes; // bottom of prism
3688 //for (int inode = 0; inode < nbNodes; inode++) {
3689 // polyedre_nodes[inode] = prevNod[inode];
3692 //quantities[1] = nbNodes; // top of prism
3693 //for (int inode = 0; inode < nbNodes; inode++) {
3694 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3697 //for (int iface = 0; iface < nbNodes; iface++) {
3698 // quantities[iface + 2] = 4;
3699 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3700 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3701 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3702 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3703 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3705 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3712 // realized for extrusion only
3713 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3714 vector<int> quantities (nbNodes + 2);
3716 quantities[0] = nbNodes; // bottom of prism
3717 for (int inode = 0; inode < nbNodes; inode++) {
3718 polyedre_nodes[inode] = prevNod[inode];
3721 quantities[1] = nbNodes; // top of prism
3722 for (int inode = 0; inode < nbNodes; inode++) {
3723 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3726 for (int iface = 0; iface < nbNodes; iface++) {
3727 quantities[iface + 2] = 4;
3728 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3729 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3730 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3731 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3732 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3734 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3738 newElems.push_back( aNewElem );
3739 myLastCreatedElems.Append(aNewElem);
3740 srcElements.Append( elem );
3743 // set new prev nodes
3744 for ( iNode = 0; iNode < nbNodes; iNode++ )
3745 prevNod[ iNode ] = nextNod[ iNode ];
3750 //=======================================================================
3752 * \brief Create 1D and 2D elements around swept elements
3753 * \param mapNewNodes - source nodes and ones generated from them
3754 * \param newElemsMap - source elements and ones generated from them
3755 * \param elemNewNodesMap - nodes generated from each node of each element
3756 * \param elemSet - all swept elements
3757 * \param nbSteps - number of sweeping steps
3758 * \param srcElements - to append elem for each generated element
3760 //=======================================================================
3762 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3763 TElemOfElemListMap & newElemsMap,
3764 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3765 TIDSortedElemSet& elemSet,
3767 SMESH_SequenceOfElemPtr& srcElements)
3769 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3770 SMESHDS_Mesh* aMesh = GetMeshDS();
3772 // Find nodes belonging to only one initial element - sweep them to get edges.
3774 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3775 for ( ; nList != mapNewNodes.end(); nList++ ) {
3776 const SMDS_MeshNode* node =
3777 static_cast<const SMDS_MeshNode*>( nList->first );
3778 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3779 int nbInitElems = 0;
3780 const SMDS_MeshElement* el = 0;
3781 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3782 while ( eIt->more() && nbInitElems < 2 ) {
3784 SMDSAbs_ElementType type = el->GetType();
3785 if ( type == SMDSAbs_Volume || type < highType ) continue;
3786 if ( type > highType ) {
3790 if ( elemSet.find(el) != elemSet.end() )
3793 if ( nbInitElems < 2 ) {
3794 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3795 if(!NotCreateEdge) {
3796 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3797 list<const SMDS_MeshElement*> newEdges;
3798 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3803 // Make a ceiling for each element ie an equal element of last new nodes.
3804 // Find free links of faces - make edges and sweep them into faces.
3806 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3807 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3808 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3809 const SMDS_MeshElement* elem = itElem->first;
3810 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3812 if ( elem->GetType() == SMDSAbs_Edge ) {
3813 // create a ceiling edge
3814 if (!elem->IsQuadratic()) {
3815 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3816 vecNewNodes[ 1 ]->second.back())) {
3817 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3818 vecNewNodes[ 1 ]->second.back()));
3819 srcElements.Append( myLastCreatedElems.Last() );
3823 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3824 vecNewNodes[ 1 ]->second.back(),
3825 vecNewNodes[ 2 ]->second.back())) {
3826 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3827 vecNewNodes[ 1 ]->second.back(),
3828 vecNewNodes[ 2 ]->second.back()));
3829 srcElements.Append( myLastCreatedElems.Last() );
3833 if ( elem->GetType() != SMDSAbs_Face )
3836 if(itElem->second.size()==0) continue;
3838 bool hasFreeLinks = false;
3840 TIDSortedElemSet avoidSet;
3841 avoidSet.insert( elem );
3843 set<const SMDS_MeshNode*> aFaceLastNodes;
3844 int iNode, nbNodes = vecNewNodes.size();
3845 if(!elem->IsQuadratic()) {
3846 // loop on the face nodes
3847 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3848 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3849 // look for free links of the face
3850 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3851 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3852 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3853 // check if a link is free
3854 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3855 hasFreeLinks = true;
3856 // make an edge and a ceiling for a new edge
3857 if ( !aMesh->FindEdge( n1, n2 )) {
3858 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3859 srcElements.Append( myLastCreatedElems.Last() );
3861 n1 = vecNewNodes[ iNode ]->second.back();
3862 n2 = vecNewNodes[ iNext ]->second.back();
3863 if ( !aMesh->FindEdge( n1, n2 )) {
3864 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3865 srcElements.Append( myLastCreatedElems.Last() );
3870 else { // elem is quadratic face
3871 int nbn = nbNodes/2;
3872 for ( iNode = 0; iNode < nbn; iNode++ ) {
3873 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3874 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3875 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3876 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3877 // check if a link is free
3878 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3879 hasFreeLinks = true;
3880 // make an edge and a ceiling for a new edge
3882 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3883 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3884 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3885 srcElements.Append( myLastCreatedElems.Last() );
3887 n1 = vecNewNodes[ iNode ]->second.back();
3888 n2 = vecNewNodes[ iNext ]->second.back();
3889 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3890 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3891 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3892 srcElements.Append( myLastCreatedElems.Last() );
3896 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3897 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3901 // sweep free links into faces
3903 if ( hasFreeLinks ) {
3904 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3905 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3907 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3908 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3909 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3910 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3912 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3913 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3915 while ( iVol++ < volNb ) v++;
3916 // find indices of free faces of a volume and their source edges
3917 list< int > freeInd;
3918 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3919 SMDS_VolumeTool vTool( *v );
3920 int iF, nbF = vTool.NbFaces();
3921 for ( iF = 0; iF < nbF; iF ++ ) {
3922 if (vTool.IsFreeFace( iF ) &&
3923 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3924 initNodeSet != faceNodeSet) // except an initial face
3926 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3928 freeInd.push_back( iF );
3929 // find source edge of a free face iF
3930 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3931 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3932 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3933 initNodeSet.begin(), initNodeSet.end(),
3934 commonNodes.begin());
3935 if ( (*v)->IsQuadratic() )
3936 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3938 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3940 if ( !srcEdges.back() )
3942 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3943 << iF << " of volume #" << vTool.ID() << endl;
3948 if ( freeInd.empty() )
3951 // create faces for all steps;
3952 // if such a face has been already created by sweep of edge,
3953 // assure that its orientation is OK
3954 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3956 vTool.SetExternalNormal();
3957 list< int >::iterator ind = freeInd.begin();
3958 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3959 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3961 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3962 int nbn = vTool.NbFaceNodes( *ind );
3964 case 3: { ///// triangle
3965 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3967 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3968 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3969 aMesh->ChangeElementNodes( f, nodes, nbn );
3972 case 4: { ///// quadrangle
3973 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3975 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3976 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3977 aMesh->ChangeElementNodes( f, nodes, nbn );
3981 if( (*v)->IsQuadratic() ) {
3982 if(nbn==6) { /////// quadratic triangle
3983 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3984 nodes[1], nodes[3], nodes[5] );
3986 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3987 nodes[1], nodes[3], nodes[5]));
3989 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3990 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3991 tmpnodes[0] = nodes[0];
3992 tmpnodes[1] = nodes[2];
3993 tmpnodes[2] = nodes[4];
3994 tmpnodes[3] = nodes[1];
3995 tmpnodes[4] = nodes[3];
3996 tmpnodes[5] = nodes[5];
3997 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
4000 else { /////// quadratic quadrangle
4001 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4002 nodes[1], nodes[3], nodes[5], nodes[7] );
4004 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4005 nodes[1], nodes[3], nodes[5], nodes[7]));
4007 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4008 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4009 tmpnodes[0] = nodes[0];
4010 tmpnodes[1] = nodes[2];
4011 tmpnodes[2] = nodes[4];
4012 tmpnodes[3] = nodes[6];
4013 tmpnodes[4] = nodes[1];
4014 tmpnodes[5] = nodes[3];
4015 tmpnodes[6] = nodes[5];
4016 tmpnodes[7] = nodes[7];
4017 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
4021 else { //////// polygon
4022 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4023 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4025 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4026 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4027 aMesh->ChangeElementNodes( f, nodes, nbn );
4030 while ( srcElements.Length() < myLastCreatedElems.Length() )
4031 srcElements.Append( *srcEdge );
4033 } // loop on free faces
4035 // go to the next volume
4037 while ( iVol++ < nbVolumesByStep ) v++;
4040 } // sweep free links into faces
4042 // Make a ceiling face with a normal external to a volume
4044 SMDS_VolumeTool lastVol( itElem->second.back() );
4046 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4048 lastVol.SetExternalNormal();
4049 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4050 int nbn = lastVol.NbFaceNodes( iF );
4053 if (!hasFreeLinks ||
4054 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4055 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4058 if (!hasFreeLinks ||
4059 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4060 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4063 if(itElem->second.back()->IsQuadratic()) {
4065 if (!hasFreeLinks ||
4066 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4067 nodes[1], nodes[3], nodes[5]) ) {
4068 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069 nodes[1], nodes[3], nodes[5]));
4073 if (!hasFreeLinks ||
4074 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4075 nodes[1], nodes[3], nodes[5], nodes[7]) )
4076 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4077 nodes[1], nodes[3], nodes[5], nodes[7]));
4081 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4082 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4083 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4087 while ( srcElements.Length() < myLastCreatedElems.Length() )
4088 srcElements.Append( myLastCreatedElems.Last() );
4090 } // loop on swept elements
4093 //=======================================================================
4094 //function : RotationSweep
4096 //=======================================================================
4098 SMESH_MeshEditor::PGroupIDs
4099 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4100 const gp_Ax1& theAxis,
4101 const double theAngle,
4102 const int theNbSteps,
4103 const double theTol,
4104 const bool theMakeGroups,
4105 const bool theMakeWalls)
4107 myLastCreatedElems.Clear();
4108 myLastCreatedNodes.Clear();
4110 // source elements for each generated one
4111 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4113 MESSAGE( "RotationSweep()");
4115 aTrsf.SetRotation( theAxis, theAngle );
4117 aTrsf2.SetRotation( theAxis, theAngle/2. );
4119 gp_Lin aLine( theAxis );
4120 double aSqTol = theTol * theTol;
4122 SMESHDS_Mesh* aMesh = GetMeshDS();
4124 TNodeOfNodeListMap mapNewNodes;
4125 TElemOfVecOfNnlmiMap mapElemNewNodes;
4126 TElemOfElemListMap newElemsMap;
4129 TIDSortedElemSet::iterator itElem;
4130 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4131 const SMDS_MeshElement* elem = *itElem;
4132 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4134 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4135 newNodesItVec.reserve( elem->NbNodes() );
4137 // loop on elem nodes
4138 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4139 while ( itN->more() ) {
4140 // check if a node has been already sweeped
4141 const SMDS_MeshNode* node = cast2Node( itN->next() );
4143 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4145 aXYZ.Coord( coord[0], coord[1], coord[2] );
4146 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4148 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4149 if ( nIt == mapNewNodes.end() ) {
4150 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4151 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4154 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4156 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4157 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4158 const SMDS_MeshNode * newNode = node;
4159 for ( int i = 0; i < theNbSteps; i++ ) {
4161 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4163 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4164 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4165 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4166 myLastCreatedNodes.Append(newNode);
4167 srcNodes.Append( node );
4168 listNewNodes.push_back( newNode );
4169 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4170 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4173 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4175 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4176 myLastCreatedNodes.Append(newNode);
4177 srcNodes.Append( node );
4178 listNewNodes.push_back( newNode );
4181 listNewNodes.push_back( newNode );
4182 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4183 listNewNodes.push_back( newNode );
4190 // if current elem is quadratic and current node is not medium
4191 // we have to check - may be it is needed to insert additional nodes
4192 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4193 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4194 if(listNewNodes.size()==theNbSteps) {
4195 listNewNodes.clear();
4197 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4199 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4200 const SMDS_MeshNode * newNode = node;
4202 for(int i = 0; i<theNbSteps; i++) {
4203 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4204 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4205 cout<<" 3 AddNode: "<<newNode;
4206 myLastCreatedNodes.Append(newNode);
4207 listNewNodes.push_back( newNode );
4208 srcNodes.Append( node );
4209 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4210 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4211 cout<<" 4 AddNode: "<<newNode;
4212 myLastCreatedNodes.Append(newNode);
4213 srcNodes.Append( node );
4214 listNewNodes.push_back( newNode );
4218 listNewNodes.push_back( newNode );
4224 newNodesItVec.push_back( nIt );
4226 // make new elements
4227 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4231 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4233 PGroupIDs newGroupIDs;
4234 if ( theMakeGroups )
4235 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4241 //=======================================================================
4242 //function : CreateNode
4244 //=======================================================================
4245 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4248 const double tolnode,
4249 SMESH_SequenceOfNode& aNodes)
4251 myLastCreatedElems.Clear();
4252 myLastCreatedNodes.Clear();
4255 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4257 // try to search in sequence of existing nodes
4258 // if aNodes.Length()>0 we 'nave to use given sequence
4259 // else - use all nodes of mesh
4260 if(aNodes.Length()>0) {
4262 for(i=1; i<=aNodes.Length(); i++) {
4263 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4264 if(P1.Distance(P2)<tolnode)
4265 return aNodes.Value(i);
4269 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4270 while(itn->more()) {
4271 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4272 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4273 if(P1.Distance(P2)<tolnode)
4278 // create new node and return it
4279 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4280 myLastCreatedNodes.Append(NewNode);
4285 //=======================================================================
4286 //function : ExtrusionSweep
4288 //=======================================================================
4290 SMESH_MeshEditor::PGroupIDs
4291 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4292 const gp_Vec& theStep,
4293 const int theNbSteps,
4294 TElemOfElemListMap& newElemsMap,
4295 const bool theMakeGroups,
4297 const double theTolerance)
4299 ExtrusParam aParams;
4300 aParams.myDir = gp_Dir(theStep);
4301 aParams.myNodes.Clear();
4302 aParams.mySteps = new TColStd_HSequenceOfReal;
4304 for(i=1; i<=theNbSteps; i++)
4305 aParams.mySteps->Append(theStep.Magnitude());
4308 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4312 //=======================================================================
4313 //function : ExtrusionSweep
4315 //=======================================================================
4317 SMESH_MeshEditor::PGroupIDs
4318 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4319 ExtrusParam& theParams,
4320 TElemOfElemListMap& newElemsMap,
4321 const bool theMakeGroups,
4323 const double theTolerance)
4325 myLastCreatedElems.Clear();
4326 myLastCreatedNodes.Clear();
4328 // source elements for each generated one
4329 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4331 SMESHDS_Mesh* aMesh = GetMeshDS();
4333 int nbsteps = theParams.mySteps->Length();
4335 TNodeOfNodeListMap mapNewNodes;
4336 //TNodeOfNodeVecMap mapNewNodes;
4337 TElemOfVecOfNnlmiMap mapElemNewNodes;
4338 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4341 TIDSortedElemSet::iterator itElem;
4342 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4343 // check element type
4344 const SMDS_MeshElement* elem = *itElem;
4345 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4348 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4349 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4350 newNodesItVec.reserve( elem->NbNodes() );
4352 // loop on elem nodes
4353 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4354 while ( itN->more() )
4356 // check if a node has been already sweeped
4357 const SMDS_MeshNode* node = cast2Node( itN->next() );
4358 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4359 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4360 if ( nIt == mapNewNodes.end() ) {
4361 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4362 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4363 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4364 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4365 //vecNewNodes.reserve(nbsteps);
4368 double coord[] = { node->X(), node->Y(), node->Z() };
4369 //int nbsteps = theParams.mySteps->Length();
4370 for ( int i = 0; i < nbsteps; i++ ) {
4371 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4372 // create additional node
4373 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4374 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4375 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4376 if( theFlags & EXTRUSION_FLAG_SEW ) {
4377 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4378 theTolerance, theParams.myNodes);
4379 listNewNodes.push_back( newNode );
4382 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4383 myLastCreatedNodes.Append(newNode);
4384 srcNodes.Append( node );
4385 listNewNodes.push_back( newNode );
4388 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4389 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4390 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4391 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4392 if( theFlags & EXTRUSION_FLAG_SEW ) {
4393 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4394 theTolerance, theParams.myNodes);
4395 listNewNodes.push_back( newNode );
4396 //vecNewNodes[i]=newNode;
4399 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4400 myLastCreatedNodes.Append(newNode);
4401 srcNodes.Append( node );
4402 listNewNodes.push_back( newNode );
4403 //vecNewNodes[i]=newNode;
4408 // if current elem is quadratic and current node is not medium
4409 // we have to check - may be it is needed to insert additional nodes
4410 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4411 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4412 if(listNewNodes.size()==nbsteps) {
4413 listNewNodes.clear();
4414 double coord[] = { node->X(), node->Y(), node->Z() };
4415 for ( int i = 0; i < nbsteps; i++ ) {
4416 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4417 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4418 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4419 if( theFlags & EXTRUSION_FLAG_SEW ) {
4420 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4421 theTolerance, theParams.myNodes);
4422 listNewNodes.push_back( newNode );
4425 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4426 myLastCreatedNodes.Append(newNode);
4427 srcNodes.Append( node );
4428 listNewNodes.push_back( newNode );
4430 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4431 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4432 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4433 if( theFlags & EXTRUSION_FLAG_SEW ) {
4434 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4435 theTolerance, theParams.myNodes);
4436 listNewNodes.push_back( newNode );
4439 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4440 myLastCreatedNodes.Append(newNode);
4441 srcNodes.Append( node );
4442 listNewNodes.push_back( newNode );
4448 newNodesItVec.push_back( nIt );
4450 // make new elements
4451 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4454 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4455 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4457 PGroupIDs newGroupIDs;
4458 if ( theMakeGroups )
4459 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4465 //=======================================================================
4466 //class : SMESH_MeshEditor_PathPoint
4467 //purpose : auxiliary class
4468 //=======================================================================
4469 class SMESH_MeshEditor_PathPoint {
4471 SMESH_MeshEditor_PathPoint() {
4472 myPnt.SetCoord(99., 99., 99.);
4473 myTgt.SetCoord(1.,0.,0.);
4477 void SetPnt(const gp_Pnt& aP3D){
4480 void SetTangent(const gp_Dir& aTgt){
4483 void SetAngle(const double& aBeta){
4486 void SetParameter(const double& aPrm){
4489 const gp_Pnt& Pnt()const{
4492 const gp_Dir& Tangent()const{
4495 double Angle()const{
4498 double Parameter()const{
4510 //=======================================================================
4511 //function : ExtrusionAlongTrack
4513 //=======================================================================
4514 SMESH_MeshEditor::Extrusion_Error
4515 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4516 SMESH_subMesh* theTrack,
4517 const SMDS_MeshNode* theN1,
4518 const bool theHasAngles,
4519 list<double>& theAngles,
4520 const bool theLinearVariation,
4521 const bool theHasRefPoint,
4522 const gp_Pnt& theRefPoint,
4523 const bool theMakeGroups)
4525 myLastCreatedElems.Clear();
4526 myLastCreatedNodes.Clear();
4529 std::list<double> aPrms;
4530 TIDSortedElemSet::iterator itElem;
4533 TopoDS_Edge aTrackEdge;
4534 TopoDS_Vertex aV1, aV2;
4536 SMDS_ElemIteratorPtr aItE;
4537 SMDS_NodeIteratorPtr aItN;
4538 SMDSAbs_ElementType aTypeE;
4540 TNodeOfNodeListMap mapNewNodes;
4543 aNbE = theElements.size();
4546 return EXTR_NO_ELEMENTS;
4548 // 1.1 Track Pattern
4551 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4553 aItE = pSubMeshDS->GetElements();
4554 while ( aItE->more() ) {
4555 const SMDS_MeshElement* pE = aItE->next();
4556 aTypeE = pE->GetType();
4557 // Pattern must contain links only
4558 if ( aTypeE != SMDSAbs_Edge )
4559 return EXTR_PATH_NOT_EDGE;
4562 list<SMESH_MeshEditor_PathPoint> fullList;
4564 const TopoDS_Shape& aS = theTrack->GetSubShape();
4565 // Sub shape for the Pattern must be an Edge or Wire
4566 if( aS.ShapeType() == TopAbs_EDGE ) {
4567 aTrackEdge = TopoDS::Edge( aS );
4568 // the Edge must not be degenerated
4569 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4570 return EXTR_BAD_PATH_SHAPE;
4571 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4572 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4573 const SMDS_MeshNode* aN1 = aItN->next();
4574 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4575 const SMDS_MeshNode* aN2 = aItN->next();
4576 // starting node must be aN1 or aN2
4577 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4578 return EXTR_BAD_STARTING_NODE;
4579 aItN = pSubMeshDS->GetNodes();
4580 while ( aItN->more() ) {
4581 const SMDS_MeshNode* pNode = aItN->next();
4582 const SMDS_EdgePosition* pEPos =
4583 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4584 double aT = pEPos->GetUParameter();
4585 aPrms.push_back( aT );
4587 //Extrusion_Error err =
4588 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4590 else if( aS.ShapeType() == TopAbs_WIRE ) {
4591 list< SMESH_subMesh* > LSM;
4592 TopTools_SequenceOfShape Edges;
4593 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4594 while(itSM->more()) {
4595 SMESH_subMesh* SM = itSM->next();
4597 const TopoDS_Shape& aS = SM->GetSubShape();
4600 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4601 int startNid = theN1->GetID();
4602 TColStd_MapOfInteger UsedNums;
4603 int NbEdges = Edges.Length();
4605 for(; i<=NbEdges; i++) {
4607 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4608 for(; itLSM!=LSM.end(); itLSM++) {
4610 if(UsedNums.Contains(k)) continue;
4611 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4612 SMESH_subMesh* locTrack = *itLSM;
4613 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4614 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4615 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4616 const SMDS_MeshNode* aN1 = aItN->next();
4617 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4618 const SMDS_MeshNode* aN2 = aItN->next();
4619 // starting node must be aN1 or aN2
4620 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4621 // 2. Collect parameters on the track edge
4623 aItN = locMeshDS->GetNodes();
4624 while ( aItN->more() ) {
4625 const SMDS_MeshNode* pNode = aItN->next();
4626 const SMDS_EdgePosition* pEPos =
4627 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4628 double aT = pEPos->GetUParameter();
4629 aPrms.push_back( aT );
4631 list<SMESH_MeshEditor_PathPoint> LPP;
4632 //Extrusion_Error err =
4633 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4634 LLPPs.push_back(LPP);
4636 // update startN for search following egde
4637 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4638 else startNid = aN1->GetID();
4642 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4643 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4644 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4645 for(; itPP!=firstList.end(); itPP++) {
4646 fullList.push_back( *itPP );
4648 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4649 fullList.pop_back();
4651 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4652 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4653 itPP = currList.begin();
4654 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4655 gp_Dir D1 = PP1.Tangent();
4656 gp_Dir D2 = PP2.Tangent();
4657 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4658 (D1.Z()+D2.Z())/2 ) );
4659 PP1.SetTangent(Dnew);
4660 fullList.push_back(PP1);
4662 for(; itPP!=firstList.end(); itPP++) {
4663 fullList.push_back( *itPP );
4665 PP1 = fullList.back();
4666 fullList.pop_back();
4668 // if wire not closed
4669 fullList.push_back(PP1);
4673 return EXTR_BAD_PATH_SHAPE;
4676 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4677 theHasRefPoint, theRefPoint, theMakeGroups);
4681 //=======================================================================
4682 //function : ExtrusionAlongTrack
4684 //=======================================================================
4685 SMESH_MeshEditor::Extrusion_Error
4686 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4687 SMESH_Mesh* theTrack,
4688 const SMDS_MeshNode* theN1,
4689 const bool theHasAngles,
4690 list<double>& theAngles,
4691 const bool theLinearVariation,
4692 const bool theHasRefPoint,
4693 const gp_Pnt& theRefPoint,
4694 const bool theMakeGroups)
4696 myLastCreatedElems.Clear();
4697 myLastCreatedNodes.Clear();
4700 std::list<double> aPrms;
4701 TIDSortedElemSet::iterator itElem;
4704 TopoDS_Edge aTrackEdge;
4705 TopoDS_Vertex aV1, aV2;
4707 SMDS_ElemIteratorPtr aItE;
4708 SMDS_NodeIteratorPtr aItN;
4709 SMDSAbs_ElementType aTypeE;
4711 TNodeOfNodeListMap mapNewNodes;
4714 aNbE = theElements.size();
4717 return EXTR_NO_ELEMENTS;
4719 // 1.1 Track Pattern
4722 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4724 aItE = pMeshDS->elementsIterator();
4725 while ( aItE->more() ) {
4726 const SMDS_MeshElement* pE = aItE->next();
4727 aTypeE = pE->GetType();
4728 // Pattern must contain links only
4729 if ( aTypeE != SMDSAbs_Edge )
4730 return EXTR_PATH_NOT_EDGE;
4733 list<SMESH_MeshEditor_PathPoint> fullList;
4735 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4736 // Sub shape for the Pattern must be an Edge or Wire
4737 if( aS.ShapeType() == TopAbs_EDGE ) {
4738 aTrackEdge = TopoDS::Edge( aS );
4739 // the Edge must not be degenerated
4740 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4741 return EXTR_BAD_PATH_SHAPE;
4742 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4743 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4744 const SMDS_MeshNode* aN1 = aItN->next();
4745 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4746 const SMDS_MeshNode* aN2 = aItN->next();
4747 // starting node must be aN1 or aN2
4748 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4749 return EXTR_BAD_STARTING_NODE;
4750 aItN = pMeshDS->nodesIterator();
4751 while ( aItN->more() ) {
4752 const SMDS_MeshNode* pNode = aItN->next();
4753 if( pNode==aN1 || pNode==aN2 ) continue;
4754 const SMDS_EdgePosition* pEPos =
4755 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4756 double aT = pEPos->GetUParameter();
4757 aPrms.push_back( aT );
4759 //Extrusion_Error err =
4760 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4762 else if( aS.ShapeType() == TopAbs_WIRE ) {
4763 list< SMESH_subMesh* > LSM;
4764 TopTools_SequenceOfShape Edges;
4765 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4766 for(; eExp.More(); eExp.Next()) {
4767 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4768 if( BRep_Tool::Degenerated(E) ) continue;
4769 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4775 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4776 int startNid = theN1->GetID();
4777 TColStd_MapOfInteger UsedNums;
4778 int NbEdges = Edges.Length();
4780 for(; i<=NbEdges; i++) {
4782 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4783 for(; itLSM!=LSM.end(); itLSM++) {
4785 if(UsedNums.Contains(k)) continue;
4786 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4787 SMESH_subMesh* locTrack = *itLSM;
4788 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4789 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4790 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4791 const SMDS_MeshNode* aN1 = aItN->next();
4792 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4793 const SMDS_MeshNode* aN2 = aItN->next();
4794 // starting node must be aN1 or aN2
4795 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4796 // 2. Collect parameters on the track edge
4798 aItN = locMeshDS->GetNodes();
4799 while ( aItN->more() ) {
4800 const SMDS_MeshNode* pNode = aItN->next();
4801 const SMDS_EdgePosition* pEPos =
4802 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4803 double aT = pEPos->GetUParameter();
4804 aPrms.push_back( aT );
4806 list<SMESH_MeshEditor_PathPoint> LPP;
4807 //Extrusion_Error err =
4808 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4809 LLPPs.push_back(LPP);
4811 // update startN for search following egde
4812 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4813 else startNid = aN1->GetID();
4817 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4818 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4819 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4820 for(; itPP!=firstList.end(); itPP++) {
4821 fullList.push_back( *itPP );
4823 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4824 fullList.pop_back();
4826 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4827 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4828 itPP = currList.begin();
4829 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4830 gp_Pnt P1 = PP1.Pnt();
4831 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4832 gp_Pnt P2 = PP2.Pnt();
4833 gp_Dir D1 = PP1.Tangent();
4834 gp_Dir D2 = PP2.Tangent();
4835 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4836 (D1.Z()+D2.Z())/2 ) );
4837 PP1.SetTangent(Dnew);
4838 fullList.push_back(PP1);
4840 for(; itPP!=currList.end(); itPP++) {
4841 fullList.push_back( *itPP );
4843 PP1 = fullList.back();
4844 fullList.pop_back();
4846 // if wire not closed
4847 fullList.push_back(PP1);
4851 return EXTR_BAD_PATH_SHAPE;
4854 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4855 theHasRefPoint, theRefPoint, theMakeGroups);
4859 //=======================================================================
4860 //function : MakeEdgePathPoints
4861 //purpose : auxilary for ExtrusionAlongTrack
4862 //=======================================================================
4863 SMESH_MeshEditor::Extrusion_Error
4864 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4865 const TopoDS_Edge& aTrackEdge,
4867 list<SMESH_MeshEditor_PathPoint>& LPP)
4869 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4871 aTolVec2=aTolVec*aTolVec;
4873 TopoDS_Vertex aV1, aV2;
4874 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4875 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4876 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4877 // 2. Collect parameters on the track edge
4878 aPrms.push_front( aT1 );
4879 aPrms.push_back( aT2 );
4882 if( FirstIsStart ) {
4893 SMESH_MeshEditor_PathPoint aPP;
4894 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4895 std::list<double>::iterator aItD = aPrms.begin();
4896 for(; aItD != aPrms.end(); ++aItD) {
4900 aC3D->D1( aT, aP3D, aVec );
4901 aL2 = aVec.SquareMagnitude();
4902 if ( aL2 < aTolVec2 )
4903 return EXTR_CANT_GET_TANGENT;
4904 gp_Dir aTgt( aVec );
4906 aPP.SetTangent( aTgt );
4907 aPP.SetParameter( aT );
4914 //=======================================================================
4915 //function : MakeExtrElements
4916 //purpose : auxilary for ExtrusionAlongTrack
4917 //=======================================================================
4918 SMESH_MeshEditor::Extrusion_Error
4919 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4920 list<SMESH_MeshEditor_PathPoint>& fullList,
4921 const bool theHasAngles,
4922 list<double>& theAngles,
4923 const bool theLinearVariation,
4924 const bool theHasRefPoint,
4925 const gp_Pnt& theRefPoint,
4926 const bool theMakeGroups)
4928 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4929 int aNbTP = fullList.size();
4930 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4932 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4933 LinearAngleVariation(aNbTP-1, theAngles);
4935 vector<double> aAngles( aNbTP );
4937 for(; j<aNbTP; ++j) {
4940 if ( theHasAngles ) {
4942 std::list<double>::iterator aItD = theAngles.begin();
4943 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4945 aAngles[j] = anAngle;
4948 // fill vector of path points with angles
4949 //aPPs.resize(fullList.size());
4951 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4952 for(; itPP!=fullList.end(); itPP++) {
4954 SMESH_MeshEditor_PathPoint PP = *itPP;
4955 PP.SetAngle(aAngles[j]);
4959 TNodeOfNodeListMap mapNewNodes;
4960 TElemOfVecOfNnlmiMap mapElemNewNodes;
4961 TElemOfElemListMap newElemsMap;
4962 TIDSortedElemSet::iterator itElem;
4965 SMDSAbs_ElementType aTypeE;
4966 // source elements for each generated one
4967 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4969 // 3. Center of rotation aV0
4970 gp_Pnt aV0 = theRefPoint;
4972 if ( !theHasRefPoint ) {
4974 aGC.SetCoord( 0.,0.,0. );
4976 itElem = theElements.begin();
4977 for ( ; itElem != theElements.end(); itElem++ ) {
4978 const SMDS_MeshElement* elem = *itElem;
4980 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4981 while ( itN->more() ) {
4982 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4987 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4988 list<const SMDS_MeshNode*> aLNx;
4989 mapNewNodes[node] = aLNx;
4991 gp_XYZ aXYZ( aX, aY, aZ );
4999 } // if (!theHasRefPoint) {
5000 mapNewNodes.clear();
5002 // 4. Processing the elements
5003 SMESHDS_Mesh* aMesh = GetMeshDS();
5005 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5006 // check element type
5007 const SMDS_MeshElement* elem = *itElem;
5008 aTypeE = elem->GetType();
5009 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5012 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5013 newNodesItVec.reserve( elem->NbNodes() );
5015 // loop on elem nodes
5017 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5018 while ( itN->more() )
5021 // check if a node has been already processed
5022 const SMDS_MeshNode* node =
5023 static_cast<const SMDS_MeshNode*>( itN->next() );
5024 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5025 if ( nIt == mapNewNodes.end() ) {
5026 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5027 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5030 aX = node->X(); aY = node->Y(); aZ = node->Z();
5032 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5033 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5034 gp_Ax1 anAx1, anAxT1T0;
5035 gp_Dir aDT1x, aDT0x, aDT1T0;
5040 aPN0.SetCoord(aX, aY, aZ);
5042 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5044 aDT0x= aPP0.Tangent();
5045 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5047 for ( j = 1; j < aNbTP; ++j ) {
5048 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5050 aDT1x = aPP1.Tangent();
5051 aAngle1x = aPP1.Angle();
5053 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5055 gp_Vec aV01x( aP0x, aP1x );
5056 aTrsf.SetTranslation( aV01x );
5059 aV1x = aV0x.Transformed( aTrsf );
5060 aPN1 = aPN0.Transformed( aTrsf );
5062 // rotation 1 [ T1,T0 ]
5063 aAngleT1T0=-aDT1x.Angle( aDT0x );
5064 if (fabs(aAngleT1T0) > aTolAng) {
5066 anAxT1T0.SetLocation( aV1x );
5067 anAxT1T0.SetDirection( aDT1T0 );
5068 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5070 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5074 if ( theHasAngles ) {
5075 anAx1.SetLocation( aV1x );
5076 anAx1.SetDirection( aDT1x );
5077 aTrsfRot.SetRotation( anAx1, aAngle1x );
5079 aPN1 = aPN1.Transformed( aTrsfRot );
5083 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5084 // create additional node
5085 double x = ( aPN1.X() + aPN0.X() )/2.;
5086 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5087 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5088 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5089 myLastCreatedNodes.Append(newNode);
5090 srcNodes.Append( node );
5091 listNewNodes.push_back( newNode );
5096 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5097 myLastCreatedNodes.Append(newNode);
5098 srcNodes.Append( node );
5099 listNewNodes.push_back( newNode );
5109 // if current elem is quadratic and current node is not medium
5110 // we have to check - may be it is needed to insert additional nodes
5111 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5112 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5113 if(listNewNodes.size()==aNbTP-1) {
5114 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5115 gp_XYZ P(node->X(), node->Y(), node->Z());
5116 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5118 for(i=0; i<aNbTP-1; i++) {
5119 const SMDS_MeshNode* N = *it;
5120 double x = ( N->X() + P.X() )/2.;
5121 double y = ( N->Y() + P.Y() )/2.;
5122 double z = ( N->Z() + P.Z() )/2.;
5123 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5124 srcNodes.Append( node );
5125 myLastCreatedNodes.Append(newN);
5128 P = gp_XYZ(N->X(),N->Y(),N->Z());
5130 listNewNodes.clear();
5131 for(i=0; i<2*(aNbTP-1); i++) {
5132 listNewNodes.push_back(aNodes[i]);
5138 newNodesItVec.push_back( nIt );
5140 // make new elements
5141 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5142 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5143 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5146 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5148 if ( theMakeGroups )
5149 generateGroups( srcNodes, srcElems, "extruded");
5155 //=======================================================================
5156 //function : LinearAngleVariation
5157 //purpose : auxilary for ExtrusionAlongTrack
5158 //=======================================================================
5159 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5160 list<double>& Angles)
5162 int nbAngles = Angles.size();
5163 if( nbSteps > nbAngles ) {
5164 vector<double> theAngles(nbAngles);
5165 list<double>::iterator it = Angles.begin();
5167 for(; it!=Angles.end(); it++) {
5169 theAngles[i] = (*it);
5172 double rAn2St = double( nbAngles ) / double( nbSteps );
5173 double angPrev = 0, angle;
5174 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5175 double angCur = rAn2St * ( iSt+1 );
5176 double angCurFloor = floor( angCur );
5177 double angPrevFloor = floor( angPrev );
5178 if ( angPrevFloor == angCurFloor )
5179 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5181 int iP = int( angPrevFloor );
5182 double angPrevCeil = ceil(angPrev);
5183 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5185 int iC = int( angCurFloor );
5186 if ( iC < nbAngles )
5187 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5189 iP = int( angPrevCeil );
5191 angle += theAngles[ iC ];
5193 res.push_back(angle);
5198 for(; it!=res.end(); it++)
5199 Angles.push_back( *it );
5204 //================================================================================
5206 * \brief Move or copy theElements applying theTrsf to their nodes
5207 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5208 * \param theTrsf - transformation to apply
5209 * \param theCopy - if true, create translated copies of theElems
5210 * \param theMakeGroups - if true and theCopy, create translated groups
5211 * \param theTargetMesh - mesh to copy translated elements into
5212 * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5214 //================================================================================
5216 SMESH_MeshEditor::PGroupIDs
5217 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5218 const gp_Trsf& theTrsf,
5220 const bool theMakeGroups,
5221 SMESH_Mesh* theTargetMesh)
5223 myLastCreatedElems.Clear();
5224 myLastCreatedNodes.Clear();
5226 bool needReverse = false;
5227 string groupPostfix;
5228 switch ( theTrsf.Form() ) {
5233 groupPostfix = "mirrored";
5236 groupPostfix = "rotated";
5238 case gp_Translation:
5239 groupPostfix = "translated";
5242 case gp_CompoundTrsf: // different scale by axis
5243 groupPostfix = "scaled";
5246 needReverse = false;
5247 groupPostfix = "transformed";
5250 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5251 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5252 SMESHDS_Mesh* aMesh = GetMeshDS();
5255 // map old node to new one
5256 TNodeNodeMap nodeMap;
5258 // elements sharing moved nodes; those of them which have all
5259 // nodes mirrored but are not in theElems are to be reversed
5260 TIDSortedElemSet inverseElemSet;
5262 // source elements for each generated one
5263 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5265 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5266 list<SMDS_MeshNode> orphanCopy; // copies of orphan nodes
5267 vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5269 if ( theElems.empty() ) // transform the whole mesh
5272 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5273 while ( eIt->more() ) theElems.insert( eIt->next() );
5275 SMDS_MeshElementIDFactory idFactory;
5276 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5277 while ( nIt->more() )
5279 const SMDS_MeshNode* node = nIt->next();
5280 if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5282 // node was not inserted into theElems because an element with the same ID
5283 // is already there. As a work around we insert a copy of node with
5284 // an ID = -<index in orphanNode>
5285 orphanCopy.push_back( *node ); // copy node
5286 SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5287 int uniqueID = -orphanNode.size();
5288 orphanNode.push_back( node );
5289 idFactory.BindID( uniqueID, nodeCopy );
5290 theElems.insert( nodeCopy );
5294 // loop on theElems to transorm nodes
5295 TIDSortedElemSet::iterator itElem;
5296 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5297 const SMDS_MeshElement* elem = *itElem;
5301 // loop on elem nodes
5302 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5303 while ( itN->more() ) {
5305 const SMDS_MeshNode* node = cast2Node( itN->next() );
5306 if ( node->GetID() < 0 )
5307 node = orphanNode[ -node->GetID() ];
5308 // check if a node has been already transformed
5309 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5310 nodeMap.insert( make_pair ( node, node ));
5311 if ( !n2n_isnew.second )
5315 coord[0] = node->X();
5316 coord[1] = node->Y();
5317 coord[2] = node->Z();
5318 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5319 if ( theTargetMesh ) {
5320 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5321 n2n_isnew.first->second = newNode;
5322 myLastCreatedNodes.Append(newNode);
5323 srcNodes.Append( node );
5325 else if ( theCopy ) {
5326 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5327 n2n_isnew.first->second = newNode;
5328 myLastCreatedNodes.Append(newNode);
5329 srcNodes.Append( node );
5332 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5333 // node position on shape becomes invalid
5334 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5335 ( SMDS_SpacePosition::originSpacePosition() );
5338 // keep inverse elements
5339 if ( !theCopy && !theTargetMesh && needReverse ) {
5340 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5341 while ( invElemIt->more() ) {
5342 const SMDS_MeshElement* iel = invElemIt->next();
5343 inverseElemSet.insert( iel );
5349 // either create new elements or reverse mirrored ones
5350 if ( !theCopy && !needReverse && !theTargetMesh )
5353 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5354 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5355 theElems.insert( *invElemIt );
5357 // replicate or reverse elements
5360 REV_TETRA = 0, // = nbNodes - 4
5361 REV_PYRAMID = 1, // = nbNodes - 4
5362 REV_PENTA = 2, // = nbNodes - 4
5364 REV_HEXA = 4, // = nbNodes - 4
5368 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5369 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5370 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5371 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5372 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5373 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5376 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5378 const SMDS_MeshElement* elem = *itElem;
5379 if ( !elem || elem->GetType() == SMDSAbs_Node )
5382 int nbNodes = elem->NbNodes();
5383 int elemType = elem->GetType();
5385 if (elem->IsPoly()) {
5386 // Polygon or Polyhedral Volume
5387 switch ( elemType ) {
5390 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5392 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5393 while (itN->more()) {
5394 const SMDS_MeshNode* node =
5395 static_cast<const SMDS_MeshNode*>(itN->next());
5396 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5397 if (nodeMapIt == nodeMap.end())
5398 break; // not all nodes transformed
5400 // reverse mirrored faces and volumes
5401 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5403 poly_nodes[iNode] = (*nodeMapIt).second;
5407 if ( iNode != nbNodes )
5408 continue; // not all nodes transformed
5410 if ( theTargetMesh ) {
5411 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5412 srcElems.Append( elem );
5414 else if ( theCopy ) {
5415 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5416 srcElems.Append( elem );
5419 aMesh->ChangePolygonNodes(elem, poly_nodes);
5423 case SMDSAbs_Volume:
5425 // ATTENTION: Reversing is not yet done!!!
5426 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5427 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5429 MESSAGE("Warning: bad volumic element");
5433 vector<const SMDS_MeshNode*> poly_nodes;
5434 vector<int> quantities;
5436 bool allTransformed = true;
5437 int nbFaces = aPolyedre->NbFaces();
5438 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5439 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5440 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5441 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5442 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5443 if (nodeMapIt == nodeMap.end()) {
5444 allTransformed = false; // not all nodes transformed
5446 poly_nodes.push_back((*nodeMapIt).second);
5449 quantities.push_back(nbFaceNodes);
5451 if ( !allTransformed )
5452 continue; // not all nodes transformed
5454 if ( theTargetMesh ) {
5455 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5456 srcElems.Append( elem );
5458 else if ( theCopy ) {
5459 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5460 srcElems.Append( elem );
5463 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5473 int* i = index[ FORWARD ];
5474 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5475 if ( elemType == SMDSAbs_Face )
5476 i = index[ REV_FACE ];
5478 i = index[ nbNodes - 4 ];
5480 if(elem->IsQuadratic()) {
5481 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5484 if(nbNodes==3) { // quadratic edge
5485 static int anIds[] = {1,0,2};
5488 else if(nbNodes==6) { // quadratic triangle
5489 static int anIds[] = {0,2,1,5,4,3};
5492 else if(nbNodes==8) { // quadratic quadrangle
5493 static int anIds[] = {0,3,2,1,7,6,5,4};
5496 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5497 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5500 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5501 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5504 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5505 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5508 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5509 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5515 // find transformed nodes
5516 vector<const SMDS_MeshNode*> nodes(nbNodes);
5518 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5519 while ( itN->more() ) {
5520 const SMDS_MeshNode* node =
5521 static_cast<const SMDS_MeshNode*>( itN->next() );
5522 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5523 if ( nodeMapIt == nodeMap.end() )
5524 break; // not all nodes transformed
5525 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5527 if ( iNode != nbNodes )
5528 continue; // not all nodes transformed
5530 if ( theTargetMesh ) {
5531 if ( SMDS_MeshElement* copy =
5532 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5533 myLastCreatedElems.Append( copy );
5534 srcElems.Append( elem );
5537 else if ( theCopy ) {
5538 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5539 srcElems.Append( elem );
5542 // reverse element as it was reversed by transformation
5544 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5548 PGroupIDs newGroupIDs;
5550 if ( theMakeGroups && theCopy ||
5551 theMakeGroups && theTargetMesh )
5552 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5557 //=======================================================================
5559 * \brief Create groups of elements made during transformation
5560 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5561 * \param elemGens - elements making corresponding myLastCreatedElems
5562 * \param postfix - to append to names of new groups
5564 //=======================================================================
5566 SMESH_MeshEditor::PGroupIDs
5567 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5568 const SMESH_SequenceOfElemPtr& elemGens,
5569 const std::string& postfix,
5570 SMESH_Mesh* targetMesh)
5572 PGroupIDs newGroupIDs( new list<int> );
5573 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5575 // Sort existing groups by types and collect their names
5577 // to store an old group and a generated new one
5578 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5579 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5581 set< string > groupNames;
5583 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5584 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5585 while ( groupIt->more() ) {
5586 SMESH_Group * group = groupIt->next();
5587 if ( !group ) continue;
5588 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5589 if ( !groupDS || groupDS->IsEmpty() ) continue;
5590 groupNames.insert( group->GetName() );
5591 groupDS->SetStoreName( group->GetName() );
5592 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5597 // loop on nodes and elements
5598 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5600 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5601 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5602 if ( gens.Length() != elems.Length() )
5603 throw SALOME_Exception(LOCALIZED("invalid args"));
5605 // loop on created elements
5606 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5608 const SMDS_MeshElement* sourceElem = gens( iElem );
5609 if ( !sourceElem ) {
5610 MESSAGE("generateGroups(): NULL source element");
5613 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5614 if ( groupsOldNew.empty() ) {
5615 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5616 ++iElem; // skip all elements made by sourceElem
5619 // collect all elements made by sourceElem
5620 list< const SMDS_MeshElement* > resultElems;
5621 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5622 if ( resElem != sourceElem )
5623 resultElems.push_back( resElem );
5624 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5625 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5626 if ( resElem != sourceElem )
5627 resultElems.push_back( resElem );
5628 // do not generate element groups from node ones
5629 if ( sourceElem->GetType() == SMDSAbs_Node &&
5630 elems( iElem )->GetType() != SMDSAbs_Node )
5633 // add resultElems to groups made by ones the sourceElem belongs to
5634 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5635 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5637 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5638 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5640 SMDS_MeshGroup* & newGroup = gOldNew->second;
5641 if ( !newGroup )// create a new group
5644 string name = oldGroup->GetStoreName();
5645 if ( !targetMesh ) {
5649 while ( !groupNames.insert( name ).second ) // name exists
5655 TCollection_AsciiString nbStr(nb+1);
5656 name.resize( name.rfind('_')+1 );
5657 name += nbStr.ToCString();
5664 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5666 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5667 newGroup = & groupDS->SMDSGroup();
5668 newGroupIDs->push_back( id );
5671 // fill in a new group
5672 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5673 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5674 newGroup->Add( *resElemIt );
5677 } // loop on created elements
5678 }// loop on nodes and elements
5683 //================================================================================
5685 * \brief Return list of group of nodes close to each other within theTolerance
5686 * Search among theNodes or in the whole mesh if theNodes is empty using
5687 * an Octree algorithm
5689 //================================================================================
5691 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
5692 const double theTolerance,
5693 TListOfListOfNodes & theGroupsOfNodes)
5695 myLastCreatedElems.Clear();
5696 myLastCreatedNodes.Clear();
5698 if ( theNodes.empty() )
5699 { // get all nodes in the mesh
5700 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5701 while ( nIt->more() )
5702 theNodes.insert( theNodes.end(),nIt->next());
5705 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5709 //=======================================================================
5711 * \brief Implementation of search for the node closest to point
5713 //=======================================================================
5715 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5717 //---------------------------------------------------------------------
5719 * \brief Constructor
5721 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5723 myMesh = ( SMESHDS_Mesh* ) theMesh;
5725 TIDSortedNodeSet nodes;
5727 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5728 while ( nIt->more() )
5729 nodes.insert( nodes.end(), nIt->next() );
5731 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5733 // get max size of a leaf box
5734 SMESH_OctreeNode* tree = myOctreeNode;
5735 while ( !tree->isLeaf() )
5737 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5741 myHalfLeafSize = tree->maxSize() / 2.;
5744 //---------------------------------------------------------------------
5746 * \brief Move node and update myOctreeNode accordingly
5748 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5750 myOctreeNode->UpdateByMoveNode( node, toPnt );
5751 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5754 //---------------------------------------------------------------------
5756 * \brief Do it's job
5758 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5760 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5761 map<double, const SMDS_MeshNode*> dist2Nodes;
5762 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5763 if ( !dist2Nodes.empty() )
5764 return dist2Nodes.begin()->second;
5765 list<const SMDS_MeshNode*> nodes;
5766 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5768 double minSqDist = DBL_MAX;
5769 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5771 // sort leafs by their distance from thePnt
5772 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5773 TDistTreeMap treeMap;
5774 list< SMESH_OctreeNode* > treeList;
5775 list< SMESH_OctreeNode* >::iterator trIt;
5776 treeList.push_back( myOctreeNode );
5778 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5779 bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5780 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5782 SMESH_OctreeNode* tree = *trIt;
5783 if ( !tree->isLeaf() ) // put children to the queue
5785 if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5786 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5787 while ( cIt->more() )
5788 treeList.push_back( cIt->next() );
5790 else if ( tree->NbNodes() ) // put a tree to the treeMap
5792 const Bnd_B3d& box = tree->getBox();
5793 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5794 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5795 if ( !it_in.second ) // not unique distance to box center
5796 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5799 // find distance after which there is no sense to check tree's
5800 double sqLimit = DBL_MAX;
5801 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5802 if ( treeMap.size() > 5 ) {
5803 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5804 const Bnd_B3d& box = closestTree->getBox();
5805 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5806 sqLimit = limit * limit;
5808 // get all nodes from trees
5809 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5810 if ( sqDist_tree->first > sqLimit )
5812 SMESH_OctreeNode* tree = sqDist_tree->second;
5813 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5816 // find closest among nodes
5817 minSqDist = DBL_MAX;
5818 const SMDS_MeshNode* closestNode = 0;
5819 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5820 for ( ; nIt != nodes.end(); ++nIt ) {
5821 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5822 if ( minSqDist > sqDist ) {
5830 //---------------------------------------------------------------------
5834 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5836 //---------------------------------------------------------------------
5838 * \brief Return the node tree
5840 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5843 SMESH_OctreeNode* myOctreeNode;
5844 SMESHDS_Mesh* myMesh;
5845 double myHalfLeafSize; // max size of a leaf box
5848 //=======================================================================
5850 * \brief Return SMESH_NodeSearcher
5852 //=======================================================================
5854 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5856 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5859 // ========================================================================
5860 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5862 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5863 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5864 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5866 //=======================================================================
5868 * \brief Octal tree of bounding boxes of elements
5870 //=======================================================================
5872 class ElementBndBoxTree : public SMESH_Octree
5876 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
5877 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5878 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5879 ~ElementBndBoxTree();
5882 ElementBndBoxTree() {}
5883 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5884 void buildChildrenData();
5885 Bnd_B3d* buildRootBox();
5887 //!< Bounding box of element
5888 struct ElementBox : public Bnd_B3d
5890 const SMDS_MeshElement* _element;
5891 int _refCount; // an ElementBox can be included in several tree branches
5892 ElementBox(const SMDS_MeshElement* elem, double tolerance);
5894 vector< ElementBox* > _elements;
5897 //================================================================================
5899 * \brief ElementBndBoxTree creation
5901 //================================================================================
5903 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
5904 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5906 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5907 _elements.reserve( nbElems );
5909 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5910 while ( elemIt->more() )
5911 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
5913 if ( _elements.size() > MaxNbElemsInLeaf )
5919 //================================================================================
5923 //================================================================================
5925 ElementBndBoxTree::~ElementBndBoxTree()
5927 for ( int i = 0; i < _elements.size(); ++i )
5928 if ( --_elements[i]->_refCount <= 0 )
5929 delete _elements[i];
5932 //================================================================================
5934 * \brief Return the maximal box
5936 //================================================================================
5938 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5940 Bnd_B3d* box = new Bnd_B3d;
5941 for ( int i = 0; i < _elements.size(); ++i )
5942 box->Add( *_elements[i] );
5946 //================================================================================
5948 * \brief Redistrubute element boxes among children
5950 //================================================================================
5952 void ElementBndBoxTree::buildChildrenData()
5954 for ( int i = 0; i < _elements.size(); ++i )
5956 for (int j = 0; j < 8; j++)
5958 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5960 _elements[i]->_refCount++;
5961 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5964 _elements[i]->_refCount--;
5968 for (int j = 0; j < 8; j++)
5970 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5971 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5972 child->myIsLeaf = true;
5974 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5975 child->_elements.resize( child->_elements.size() ); // compact
5979 //================================================================================
5981 * \brief Return elements which can include the point
5983 //================================================================================
5985 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5986 TIDSortedElemSet& foundElems)
5988 if ( level() && getBox().IsOut( point.XYZ() ))
5993 for ( int i = 0; i < _elements.size(); ++i )
5994 if ( !_elements[i]->IsOut( point.XYZ() ))
5995 foundElems.insert( _elements[i]->_element );
5999 for (int i = 0; i < 8; i++)
6000 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6004 //================================================================================
6006 * \brief Return elements which can be intersected by the line
6008 //================================================================================
6010 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6011 TIDSortedElemSet& foundElems)
6013 if ( level() && getBox().IsOut( line ))
6018 for ( int i = 0; i < _elements.size(); ++i )
6019 if ( !_elements[i]->IsOut( line ))
6020 foundElems.insert( _elements[i]->_element );
6024 for (int i = 0; i < 8; i++)
6025 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6029 //================================================================================
6031 * \brief Construct the element box
6033 //================================================================================
6035 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6039 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6040 while ( nIt->more() )
6041 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6042 Enlarge( tolerance );
6047 //=======================================================================
6049 * \brief Implementation of search for the elements by point and
6050 * of classification of point in 2D mesh
6052 //=======================================================================
6054 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6056 SMESHDS_Mesh* _mesh;
6057 ElementBndBoxTree* _ebbTree;
6058 SMESH_NodeSearcherImpl* _nodeSearcher;
6059 SMDSAbs_ElementType _elementType;
6061 bool _outerFacesFound;
6062 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6064 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6065 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6066 ~SMESH_ElementSearcherImpl()
6068 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6069 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6071 virtual int FindElementsByPoint(const gp_Pnt& point,
6072 SMDSAbs_ElementType type,
6073 vector< const SMDS_MeshElement* >& foundElements);
6074 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6076 void GetElementsNearLine( const gp_Ax1& line,
6077 SMDSAbs_ElementType type,
6078 vector< const SMDS_MeshElement* >& foundElems);
6079 double getTolerance();
6080 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6081 const double tolerance, double & param);
6082 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6083 bool isOuterBoundary(const SMDS_MeshElement* face) const
6085 return _outerFaces.empty() || _outerFaces.count(face);
6087 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6089 const SMDS_MeshElement* _face;
6091 bool _coincides; //!< the line lays in face plane
6092 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6093 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6095 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6098 TIDSortedElemSet _faces;
6099 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6100 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6104 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6106 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6107 << ", _coincides="<<i._coincides << ")";
6110 //=======================================================================
6112 * \brief define tolerance for search
6114 //=======================================================================
6116 double SMESH_ElementSearcherImpl::getTolerance()
6118 if ( _tolerance < 0 )
6120 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6123 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6125 double boxSize = _nodeSearcher->getTree()->maxSize();
6126 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6128 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6130 double boxSize = _ebbTree->maxSize();
6131 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6133 if ( _tolerance == 0 )
6135 // define tolerance by size of a most complex element
6136 int complexType = SMDSAbs_Volume;
6137 while ( complexType > SMDSAbs_All &&
6138 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6140 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6143 if ( complexType == int( SMDSAbs_Node ))
6145 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6147 if ( meshInfo.NbNodes() > 2 )
6148 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6152 const SMDS_MeshElement* elem =
6153 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6154 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6155 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6156 while ( nodeIt->more() )
6158 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6159 elemSize = max( dist, elemSize );
6162 _tolerance = 1e-4 * elemSize;
6168 //================================================================================
6170 * \brief Find intersection of the line and an edge of face and return parameter on line
6172 //================================================================================
6174 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6175 const SMDS_MeshElement* face,
6182 GeomAPI_ExtremaCurveCurve anExtCC;
6183 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6185 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6186 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6188 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6189 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6190 anExtCC.Init( lineCurve, edge);
6191 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6193 Quantity_Parameter pl, pe;
6194 anExtCC.LowerDistanceParameters( pl, pe );
6196 if ( ++nbInts == 2 )
6200 if ( nbInts > 0 ) param /= nbInts;
6203 //================================================================================
6205 * \brief Find all faces belonging to the outer boundary of mesh
6207 //================================================================================
6209 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6211 if ( _outerFacesFound ) return;
6213 // Collect all outer faces by passing from one outer face to another via their links
6214 // and BTW find out if there are internal faces at all.
6216 // checked links and links where outer boundary meets internal one
6217 set< SMESH_TLink > visitedLinks, seamLinks;
6219 // links to treat with already visited faces sharing them
6220 list < TFaceLink > startLinks;
6222 // load startLinks with the first outerFace
6223 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6224 _outerFaces.insert( outerFace );
6226 TIDSortedElemSet emptySet;
6227 while ( !startLinks.empty() )
6229 const SMESH_TLink& link = startLinks.front()._link;
6230 TIDSortedElemSet& faces = startLinks.front()._faces;
6232 outerFace = *faces.begin();
6233 // find other faces sharing the link
6234 const SMDS_MeshElement* f;
6235 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6238 // select another outer face among the found
6239 const SMDS_MeshElement* outerFace2 = 0;
6240 if ( faces.size() == 2 )
6242 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6244 else if ( faces.size() > 2 )
6246 seamLinks.insert( link );
6248 // link direction within the outerFace
6249 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6250 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6251 int i1 = outerFace->GetNodeIndex( link.node1() );
6252 int i2 = outerFace->GetNodeIndex( link.node2() );
6253 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6254 if ( rev ) n1n2.Reverse();
6256 gp_XYZ ofNorm, fNorm;
6257 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6259 // direction from the link inside outerFace
6260 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6261 // sort all other faces by angle with the dirInOF
6262 map< double, const SMDS_MeshElement* > angle2Face;
6263 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6264 for ( ; face != faces.end(); ++face )
6266 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6268 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6269 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6270 if ( angle < 0 ) angle += 2*PI;
6271 angle2Face.insert( make_pair( angle, *face ));
6273 if ( !angle2Face.empty() )
6274 outerFace2 = angle2Face.begin()->second;
6277 // store the found outer face and add its links to continue seaching from
6280 _outerFaces.insert( outerFace );
6281 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6282 for ( int i = 0; i < nbNodes; ++i )
6284 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6285 if ( visitedLinks.insert( link2 ).second )
6286 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6289 startLinks.pop_front();
6291 _outerFacesFound = true;
6293 if ( !seamLinks.empty() )
6295 // There are internal boundaries touching the outher one,
6296 // find all faces of internal boundaries in order to find
6297 // faces of boundaries of holes, if any.
6302 _outerFaces.clear();
6306 //=======================================================================
6308 * \brief Find elements of given type where the given point is IN or ON.
6309 * Returns nb of found elements and elements them-selves.
6311 * 'ALL' type means elements of any type excluding nodes and 0D elements
6313 //=======================================================================
6315 int SMESH_ElementSearcherImpl::
6316 FindElementsByPoint(const gp_Pnt& point,
6317 SMDSAbs_ElementType type,
6318 vector< const SMDS_MeshElement* >& foundElements)
6320 foundElements.clear();
6322 double tolerance = getTolerance();
6324 // =================================================================================
6325 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6327 if ( !_nodeSearcher )
6328 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6330 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6331 if ( !closeNode ) return foundElements.size();
6333 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6334 return foundElements.size(); // to far from any node
6336 if ( type == SMDSAbs_Node )
6338 foundElements.push_back( closeNode );
6342 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6343 while ( elemIt->more() )
6344 foundElements.push_back( elemIt->next() );
6347 // =================================================================================
6348 else // elements more complex than 0D
6350 if ( !_ebbTree || _elementType != type )
6352 if ( _ebbTree ) delete _ebbTree;
6353 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6355 TIDSortedElemSet suspectElems;
6356 _ebbTree->getElementsNearPoint( point, suspectElems );
6357 TIDSortedElemSet::iterator elem = suspectElems.begin();
6358 for ( ; elem != suspectElems.end(); ++elem )
6359 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6360 foundElements.push_back( *elem );
6362 return foundElements.size();
6365 //================================================================================
6367 * \brief Classify the given point in the closed 2D mesh
6369 //================================================================================
6371 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6373 double tolerance = getTolerance();
6374 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6376 if ( _ebbTree ) delete _ebbTree;
6377 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6379 // Algo: analyse transition of a line starting at the point through mesh boundary;
6380 // try three lines parallel to axis of the coordinate system and perform rough
6381 // analysis. If solution is not clear perform thorough analysis.
6383 const int nbAxes = 3;
6384 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6385 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6386 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6387 multimap< int, int > nbInt2Axis; // to find the simplest case
6388 for ( int axis = 0; axis < nbAxes; ++axis )
6390 gp_Ax1 lineAxis( point, axisDir[axis]);
6391 gp_Lin line ( lineAxis );
6393 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6394 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6396 // Intersect faces with the line
6398 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6399 TIDSortedElemSet::iterator face = suspectFaces.begin();
6400 for ( ; face != suspectFaces.end(); ++face )
6404 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6405 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6407 // perform intersection
6408 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6409 if ( !intersection.IsDone() )
6411 if ( intersection.IsInQuadric() )
6413 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6415 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6417 gp_Pnt intersectionPoint = intersection.Point(1);
6418 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6419 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6422 // Analyse intersections roughly
6424 int nbInter = u2inters.size();
6428 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6429 if ( nbInter == 1 ) // not closed mesh
6430 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6432 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6435 if ( (f<0) == (l<0) )
6438 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6439 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6440 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6443 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6445 if ( _outerFacesFound ) break; // pass to thorough analysis
6447 } // three attempts - loop on CS axes
6449 // Analyse intersections thoroughly.
6450 // We make two loops maximum, on the first one we only exclude touching intersections,
6451 // on the second, if situation is still unclear, we gather and use information on
6452 // position of faces (internal or outer). If faces position is already gathered,
6453 // we make the second loop right away.
6455 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6457 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6458 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6460 int axis = nb_axis->second;
6461 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6463 gp_Ax1 lineAxis( point, axisDir[axis]);
6464 gp_Lin line ( lineAxis );
6466 // add tangent intersections to u2inters
6468 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6469 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6470 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6471 u2inters.insert(make_pair( param, *tgtInt ));
6472 tangentInters[ axis ].clear();
6474 // Count intersections before and after the point excluding touching ones.
6475 // If hasPositionInfo we count intersections of outer boundary only
6477 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6478 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6479 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6480 bool ok = ! u_int1->second._coincides;
6481 while ( ok && u_int1 != u2inters.end() )
6483 double u = u_int1->first;
6484 bool touchingInt = false;
6485 if ( ++u_int2 != u2inters.end() )
6487 // skip intersections at the same point (if the line passes through edge or node)
6489 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6495 // skip tangent intersections
6497 const SMDS_MeshElement* prevFace = u_int1->second._face;
6498 while ( ok && u_int2->second._coincides )
6500 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6506 ok = ( u_int2 != u2inters.end() );
6511 // skip intersections at the same point after tangent intersections
6514 double u2 = u_int2->first;
6516 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6522 // decide if we skipped a touching intersection
6523 if ( nbSamePnt + nbTgt > 0 )
6525 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6526 map< double, TInters >::iterator u_int = u_int1;
6527 for ( ; u_int != u_int2; ++u_int )
6529 if ( u_int->second._coincides ) continue;
6530 double dot = u_int->second._faceNorm * line.Direction();
6531 if ( dot > maxDot ) maxDot = dot;
6532 if ( dot < minDot ) minDot = dot;
6534 touchingInt = ( minDot*maxDot < 0 );
6539 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6550 u_int1 = u_int2; // to next intersection
6552 } // loop on intersections with one line
6556 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6559 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6562 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6563 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6565 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6568 if ( (f<0) == (l<0) )
6571 if ( hasPositionInfo )
6572 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6574 } // loop on intersections of the tree lines - thorough analysis
6576 if ( !hasPositionInfo )
6578 // gather info on faces position - is face in the outer boundary or not
6579 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6580 findOuterBoundary( u2inters.begin()->second._face );
6583 } // two attempts - with and w/o faces position info in the mesh
6585 return TopAbs_UNKNOWN;
6588 //=======================================================================
6590 * \brief Return elements possibly intersecting the line
6592 //=======================================================================
6594 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
6595 SMDSAbs_ElementType type,
6596 vector< const SMDS_MeshElement* >& foundElems)
6598 if ( !_ebbTree || _elementType != type )
6600 if ( _ebbTree ) delete _ebbTree;
6601 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6603 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6604 _ebbTree->getElementsNearLine( line, suspectFaces );
6605 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6608 //=======================================================================
6610 * \brief Return SMESH_ElementSearcher
6612 //=======================================================================
6614 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6616 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6619 //=======================================================================
6621 * \brief Return true if the point is IN or ON of the element
6623 //=======================================================================
6625 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6627 if ( element->GetType() == SMDSAbs_Volume)
6629 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6632 // get ordered nodes
6634 vector< gp_XYZ > xyz;
6636 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6637 if ( element->IsQuadratic() )
6638 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6639 nodeIt = f->interlacedNodesElemIterator();
6640 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6641 nodeIt = e->interlacedNodesElemIterator();
6643 while ( nodeIt->more() )
6644 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6646 int i, nbNodes = element->NbNodes();
6648 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6650 // compute face normal
6651 gp_Vec faceNorm(0,0,0);
6652 xyz.push_back( xyz.front() );
6653 for ( i = 0; i < nbNodes; ++i )
6655 gp_Vec edge1( xyz[i+1], xyz[i]);
6656 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6657 faceNorm += edge1 ^ edge2;
6659 double normSize = faceNorm.Magnitude();
6660 if ( normSize <= tol )
6662 // degenerated face: point is out if it is out of all face edges
6663 for ( i = 0; i < nbNodes; ++i )
6665 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6666 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6667 SMDS_MeshEdge edge( &n1, &n2 );
6668 if ( !isOut( &edge, point, tol ))
6673 faceNorm /= normSize;
6675 // check if the point lays on face plane
6676 gp_Vec n2p( xyz[0], point );
6677 if ( fabs( n2p * faceNorm ) > tol )
6678 return true; // not on face plane
6680 // check if point is out of face boundary:
6681 // define it by closest transition of a ray point->infinity through face boundary
6682 // on the face plane.
6683 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6684 // to find intersections of the ray with the boundary.
6686 gp_Vec plnNorm = ray ^ faceNorm;
6687 normSize = plnNorm.Magnitude();
6688 if ( normSize <= tol ) return false; // point coincides with the first node
6689 plnNorm /= normSize;
6690 // for each node of the face, compute its signed distance to the plane
6691 vector<double> dist( nbNodes + 1);
6692 for ( i = 0; i < nbNodes; ++i )
6694 gp_Vec n2p( xyz[i], point );
6695 dist[i] = n2p * plnNorm;
6697 dist.back() = dist.front();
6698 // find the closest intersection
6700 double rClosest, distClosest = 1e100;;
6702 for ( i = 0; i < nbNodes; ++i )
6705 if ( fabs( dist[i]) < tol )
6707 else if ( fabs( dist[i+1]) < tol )
6709 else if ( dist[i] * dist[i+1] < 0 )
6710 r = dist[i] / ( dist[i] - dist[i+1] );
6712 continue; // no intersection
6713 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6714 gp_Vec p2int ( point, pInt);
6715 if ( p2int * ray > -tol ) // right half-space
6717 double intDist = p2int.SquareMagnitude();
6718 if ( intDist < distClosest )
6723 distClosest = intDist;
6728 return true; // no intesections - out
6730 // analyse transition
6731 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6732 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6733 gp_Vec p2int ( point, pClosest );
6734 bool out = (edgeNorm * p2int) < -tol;
6735 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6738 // ray pass through a face node; analyze transition through an adjacent edge
6739 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6740 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6741 gp_Vec edgeAdjacent( p1, p2 );
6742 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6743 bool out2 = (edgeNorm2 * p2int) < -tol;
6745 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6746 return covexCorner ? (out || out2) : (out && out2);
6748 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6750 // point is out of edge if it is NOT ON any straight part of edge
6751 // (we consider quadratic edge as being composed of two straight parts)
6752 for ( i = 1; i < nbNodes; ++i )
6754 gp_Vec edge( xyz[i-1], xyz[i]);
6755 gp_Vec n1p ( xyz[i-1], point);
6756 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6759 gp_Vec n2p( xyz[i], point );
6760 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6762 return false; // point is ON this part
6766 // Node or 0D element -------------------------------------------------------------------------
6768 gp_Vec n2p ( xyz[0], point );
6769 return n2p.Magnitude() <= tol;
6774 //=======================================================================
6775 //function : SimplifyFace
6777 //=======================================================================
6778 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6779 vector<const SMDS_MeshNode *>& poly_nodes,
6780 vector<int>& quantities) const
6782 int nbNodes = faceNodes.size();
6787 set<const SMDS_MeshNode*> nodeSet;
6789 // get simple seq of nodes
6790 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6791 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6792 int iSimple = 0, nbUnique = 0;
6794 simpleNodes[iSimple++] = faceNodes[0];
6796 for (int iCur = 1; iCur < nbNodes; iCur++) {
6797 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6798 simpleNodes[iSimple++] = faceNodes[iCur];
6799 if (nodeSet.insert( faceNodes[iCur] ).second)
6803 int nbSimple = iSimple;
6804 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6814 bool foundLoop = (nbSimple > nbUnique);
6817 set<const SMDS_MeshNode*> loopSet;
6818 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6819 const SMDS_MeshNode* n = simpleNodes[iSimple];
6820 if (!loopSet.insert( n ).second) {
6824 int iC = 0, curLast = iSimple;
6825 for (; iC < curLast; iC++) {
6826 if (simpleNodes[iC] == n) break;
6828 int loopLen = curLast - iC;
6830 // create sub-element
6832 quantities.push_back(loopLen);
6833 for (; iC < curLast; iC++) {
6834 poly_nodes.push_back(simpleNodes[iC]);
6837 // shift the rest nodes (place from the first loop position)
6838 for (iC = curLast + 1; iC < nbSimple; iC++) {
6839 simpleNodes[iC - loopLen] = simpleNodes[iC];
6841 nbSimple -= loopLen;
6844 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6845 } // while (foundLoop)
6849 quantities.push_back(iSimple);
6850 for (int i = 0; i < iSimple; i++)
6851 poly_nodes.push_back(simpleNodes[i]);
6857 //=======================================================================
6858 //function : MergeNodes
6859 //purpose : In each group, the cdr of nodes are substituted by the first one
6861 //=======================================================================
6863 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6865 myLastCreatedElems.Clear();
6866 myLastCreatedNodes.Clear();
6868 SMESHDS_Mesh* aMesh = GetMeshDS();
6870 TNodeNodeMap nodeNodeMap; // node to replace - new node
6871 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6872 list< int > rmElemIds, rmNodeIds;
6874 // Fill nodeNodeMap and elems
6876 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6877 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6878 list<const SMDS_MeshNode*>& nodes = *grIt;
6879 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6880 const SMDS_MeshNode* nToKeep = *nIt;
6881 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6882 const SMDS_MeshNode* nToRemove = *nIt;
6883 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6884 if ( nToRemove != nToKeep ) {
6885 rmNodeIds.push_back( nToRemove->GetID() );
6886 AddToSameGroups( nToKeep, nToRemove, aMesh );
6889 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6890 while ( invElemIt->more() ) {
6891 const SMDS_MeshElement* elem = invElemIt->next();
6896 // Change element nodes or remove an element
6898 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6899 for ( ; eIt != elems.end(); eIt++ ) {
6900 const SMDS_MeshElement* elem = *eIt;
6901 int nbNodes = elem->NbNodes();
6902 int aShapeId = FindShape( elem );
6904 set<const SMDS_MeshNode*> nodeSet;
6905 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6906 int iUnique = 0, iCur = 0, nbRepl = 0;
6907 vector<int> iRepl( nbNodes );
6909 // get new seq of nodes
6910 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6911 while ( itN->more() ) {
6912 const SMDS_MeshNode* n =
6913 static_cast<const SMDS_MeshNode*>( itN->next() );
6915 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6916 if ( nnIt != nodeNodeMap.end() ) { // n sticks
6918 // BUG 0020185: begin
6920 bool stopRecur = false;
6921 set<const SMDS_MeshNode*> nodesRecur;
6922 nodesRecur.insert(n);
6923 while (!stopRecur) {
6924 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6925 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6926 n = (*nnIt_i).second;
6927 if (!nodesRecur.insert(n).second) {
6928 // error: recursive dependancy
6937 iRepl[ nbRepl++ ] = iCur;
6939 curNodes[ iCur ] = n;
6940 bool isUnique = nodeSet.insert( n ).second;
6942 uniqueNodes[ iUnique++ ] = n;
6946 // Analyse element topology after replacement
6949 int nbUniqueNodes = nodeSet.size();
6950 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6951 // Polygons and Polyhedral volumes
6952 if (elem->IsPoly()) {
6954 if (elem->GetType() == SMDSAbs_Face) {
6956 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6958 for (; inode < nbNodes; inode++) {
6959 face_nodes[inode] = curNodes[inode];
6962 vector<const SMDS_MeshNode *> polygons_nodes;
6963 vector<int> quantities;
6964 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6968 for (int iface = 0; iface < nbNew - 1; iface++) {
6969 int nbNodes = quantities[iface];
6970 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6971 for (int ii = 0; ii < nbNodes; ii++, inode++) {
6972 poly_nodes[ii] = polygons_nodes[inode];
6974 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6975 myLastCreatedElems.Append(newElem);
6977 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6979 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6982 rmElemIds.push_back(elem->GetID());
6986 else if (elem->GetType() == SMDSAbs_Volume) {
6987 // Polyhedral volume
6988 if (nbUniqueNodes < 4) {
6989 rmElemIds.push_back(elem->GetID());
6992 // each face has to be analized in order to check volume validity
6993 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6994 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6996 int nbFaces = aPolyedre->NbFaces();
6998 vector<const SMDS_MeshNode *> poly_nodes;
6999 vector<int> quantities;
7001 for (int iface = 1; iface <= nbFaces; iface++) {
7002 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7003 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7005 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7006 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7007 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7008 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7009 faceNode = (*nnIt).second;
7011 faceNodes[inode - 1] = faceNode;
7014 SimplifyFace(faceNodes, poly_nodes, quantities);
7017 if (quantities.size() > 3) {
7018 // to be done: remove coincident faces
7021 if (quantities.size() > 3)
7022 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7024 rmElemIds.push_back(elem->GetID());
7028 rmElemIds.push_back(elem->GetID());
7039 switch ( nbNodes ) {
7040 case 2: ///////////////////////////////////// EDGE
7041 isOk = false; break;
7042 case 3: ///////////////////////////////////// TRIANGLE
7043 isOk = false; break;
7045 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7047 else { //////////////////////////////////// QUADRANGLE
7048 if ( nbUniqueNodes < 3 )
7050 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7051 isOk = false; // opposite nodes stick
7054 case 6: ///////////////////////////////////// PENTAHEDRON
7055 if ( nbUniqueNodes == 4 ) {
7056 // ---------------------------------> tetrahedron
7058 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7059 // all top nodes stick: reverse a bottom
7060 uniqueNodes[ 0 ] = curNodes [ 1 ];
7061 uniqueNodes[ 1 ] = curNodes [ 0 ];
7063 else if (nbRepl == 3 &&
7064 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7065 // all bottom nodes stick: set a top before
7066 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7067 uniqueNodes[ 0 ] = curNodes [ 3 ];
7068 uniqueNodes[ 1 ] = curNodes [ 4 ];
7069 uniqueNodes[ 2 ] = curNodes [ 5 ];
7071 else if (nbRepl == 4 &&
7072 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7073 // a lateral face turns into a line: reverse a bottom
7074 uniqueNodes[ 0 ] = curNodes [ 1 ];
7075 uniqueNodes[ 1 ] = curNodes [ 0 ];
7080 else if ( nbUniqueNodes == 5 ) {
7081 // PENTAHEDRON --------------------> 2 tetrahedrons
7082 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7083 // a bottom node sticks with a linked top one
7085 SMDS_MeshElement* newElem =
7086 aMesh->AddVolume(curNodes[ 3 ],
7089 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7090 myLastCreatedElems.Append(newElem);
7092 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7093 // 2. : reverse a bottom
7094 uniqueNodes[ 0 ] = curNodes [ 1 ];
7095 uniqueNodes[ 1 ] = curNodes [ 0 ];
7105 if(elem->IsQuadratic()) { // Quadratic quadrangle
7118 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7119 uniqueNodes[0] = curNodes[0];
7120 uniqueNodes[1] = curNodes[2];
7121 uniqueNodes[2] = curNodes[3];
7122 uniqueNodes[3] = curNodes[5];
7123 uniqueNodes[4] = curNodes[6];
7124 uniqueNodes[5] = curNodes[7];
7127 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7128 uniqueNodes[0] = curNodes[0];
7129 uniqueNodes[1] = curNodes[1];
7130 uniqueNodes[2] = curNodes[2];
7131 uniqueNodes[3] = curNodes[4];
7132 uniqueNodes[4] = curNodes[5];
7133 uniqueNodes[5] = curNodes[6];
7136 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7137 uniqueNodes[0] = curNodes[1];
7138 uniqueNodes[1] = curNodes[2];
7139 uniqueNodes[2] = curNodes[3];
7140 uniqueNodes[3] = curNodes[5];
7141 uniqueNodes[4] = curNodes[6];
7142 uniqueNodes[5] = curNodes[0];
7145 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7146 uniqueNodes[0] = curNodes[0];
7147 uniqueNodes[1] = curNodes[1];
7148 uniqueNodes[2] = curNodes[3];
7149 uniqueNodes[3] = curNodes[4];
7150 uniqueNodes[4] = curNodes[6];
7151 uniqueNodes[5] = curNodes[7];
7154 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7155 uniqueNodes[0] = curNodes[0];
7156 uniqueNodes[1] = curNodes[2];
7157 uniqueNodes[2] = curNodes[3];
7158 uniqueNodes[3] = curNodes[1];
7159 uniqueNodes[4] = curNodes[6];
7160 uniqueNodes[5] = curNodes[7];
7163 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7164 uniqueNodes[0] = curNodes[0];
7165 uniqueNodes[1] = curNodes[1];
7166 uniqueNodes[2] = curNodes[2];
7167 uniqueNodes[3] = curNodes[4];
7168 uniqueNodes[4] = curNodes[5];
7169 uniqueNodes[5] = curNodes[7];
7172 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7173 uniqueNodes[0] = curNodes[0];
7174 uniqueNodes[1] = curNodes[1];
7175 uniqueNodes[2] = curNodes[3];
7176 uniqueNodes[3] = curNodes[4];
7177 uniqueNodes[4] = curNodes[2];
7178 uniqueNodes[5] = curNodes[7];
7181 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7182 uniqueNodes[0] = curNodes[0];
7183 uniqueNodes[1] = curNodes[1];
7184 uniqueNodes[2] = curNodes[2];
7185 uniqueNodes[3] = curNodes[4];
7186 uniqueNodes[4] = curNodes[5];
7187 uniqueNodes[5] = curNodes[3];
7193 //////////////////////////////////// HEXAHEDRON
7195 SMDS_VolumeTool hexa (elem);
7196 hexa.SetExternalNormal();
7197 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7198 //////////////////////// ---> tetrahedron
7199 for ( int iFace = 0; iFace < 6; iFace++ ) {
7200 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7201 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7202 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7203 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7204 // one face turns into a point ...
7205 int iOppFace = hexa.GetOppFaceIndex( iFace );
7206 ind = hexa.GetFaceNodesIndices( iOppFace );
7208 iUnique = 2; // reverse a tetrahedron bottom
7209 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7210 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7212 else if ( iUnique >= 0 )
7213 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7215 if ( nbStick == 1 ) {
7216 // ... and the opposite one - into a triangle.
7218 ind = hexa.GetFaceNodesIndices( iFace );
7219 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7226 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7227 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7228 for ( int iFace = 0; iFace < 6; iFace++ ) {
7229 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7230 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7231 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7232 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7233 // one face turns into a point ...
7234 int iOppFace = hexa.GetOppFaceIndex( iFace );
7235 ind = hexa.GetFaceNodesIndices( iOppFace );
7237 iUnique = 2; // reverse a tetrahedron 1 bottom
7238 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7239 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7241 else if ( iUnique >= 0 )
7242 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7244 if ( nbStick == 0 ) {
7245 // ... and the opposite one is a quadrangle
7247 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7248 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7251 SMDS_MeshElement* newElem =
7252 aMesh->AddVolume(curNodes[ind[ 0 ]],
7255 curNodes[indTop[ 0 ]]);
7256 myLastCreatedElems.Append(newElem);
7258 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7265 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7266 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7267 // find indices of quad and tri faces
7268 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7269 for ( iFace = 0; iFace < 6; iFace++ ) {
7270 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7272 for ( iCur = 0; iCur < 4; iCur++ )
7273 nodeSet.insert( curNodes[ind[ iCur ]] );
7274 nbUniqueNodes = nodeSet.size();
7275 if ( nbUniqueNodes == 3 )
7276 iTriFace[ nbTri++ ] = iFace;
7277 else if ( nbUniqueNodes == 4 )
7278 iQuadFace[ nbQuad++ ] = iFace;
7280 if (nbQuad == 2 && nbTri == 4 &&
7281 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7282 // 2 opposite quadrangles stuck with a diagonal;
7283 // sample groups of merged indices: (0-4)(2-6)
7284 // --------------------------------------------> 2 tetrahedrons
7285 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7286 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7287 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7288 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7289 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7290 // stuck with 0-2 diagonal
7298 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7299 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7300 // stuck with 1-3 diagonal
7312 uniqueNodes[ 0 ] = curNodes [ i0 ];
7313 uniqueNodes[ 1 ] = curNodes [ i1d ];
7314 uniqueNodes[ 2 ] = curNodes [ i3d ];
7315 uniqueNodes[ 3 ] = curNodes [ i0t ];
7318 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7322 myLastCreatedElems.Append(newElem);
7324 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7327 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7328 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7329 // --------------------------------------------> prism
7330 // find 2 opposite triangles
7332 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7333 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7334 // find indices of kept and replaced nodes
7335 // and fill unique nodes of 2 opposite triangles
7336 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7337 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7338 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7339 // fill unique nodes
7342 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7343 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7344 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7346 // iCur of a linked node of the opposite face (make normals co-directed):
7347 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7348 // check that correspondent corners of triangles are linked
7349 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7352 uniqueNodes[ iUnique ] = n;
7353 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7362 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7368 } // switch ( nbNodes )
7370 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7373 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7374 // Change nodes of polyedre
7375 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7376 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7378 int nbFaces = aPolyedre->NbFaces();
7380 vector<const SMDS_MeshNode *> poly_nodes;
7381 vector<int> quantities (nbFaces);
7383 for (int iface = 1; iface <= nbFaces; iface++) {
7384 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7385 quantities[iface - 1] = nbFaceNodes;
7387 for (inode = 1; inode <= nbFaceNodes; inode++) {
7388 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7390 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7391 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7392 curNode = (*nnIt).second;
7394 poly_nodes.push_back(curNode);
7397 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7401 // Change regular element or polygon
7402 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7406 // Remove invalid regular element or invalid polygon
7407 rmElemIds.push_back( elem->GetID() );
7410 } // loop on elements
7412 // Remove equal nodes and bad elements
7414 Remove( rmNodeIds, true );
7415 Remove( rmElemIds, false );
7420 // ========================================================
7421 // class : SortableElement
7422 // purpose : allow sorting elements basing on their nodes
7423 // ========================================================
7424 class SortableElement : public set <const SMDS_MeshElement*>
7428 SortableElement( const SMDS_MeshElement* theElem )
7431 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7432 while ( nodeIt->more() )
7433 this->insert( nodeIt->next() );
7436 const SMDS_MeshElement* Get() const
7439 void Set(const SMDS_MeshElement* e) const
7444 mutable const SMDS_MeshElement* myElem;
7447 //=======================================================================
7448 //function : FindEqualElements
7449 //purpose : Return list of group of elements built on the same nodes.
7450 // Search among theElements or in the whole mesh if theElements is empty
7451 //=======================================================================
7452 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7453 TListOfListOfElementsID & theGroupsOfElementsID)
7455 myLastCreatedElems.Clear();
7456 myLastCreatedNodes.Clear();
7458 typedef set<const SMDS_MeshElement*> TElemsSet;
7459 typedef map< SortableElement, int > TMapOfNodeSet;
7460 typedef list<int> TGroupOfElems;
7463 if ( theElements.empty() )
7464 { // get all elements in the mesh
7465 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7466 while ( eIt->more() )
7467 elems.insert( elems.end(), eIt->next());
7470 elems = theElements;
7472 vector< TGroupOfElems > arrayOfGroups;
7473 TGroupOfElems groupOfElems;
7474 TMapOfNodeSet mapOfNodeSet;
7476 TElemsSet::iterator elemIt = elems.begin();
7477 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7478 const SMDS_MeshElement* curElem = *elemIt;
7479 SortableElement SE(curElem);
7482 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7483 if( !(pp.second) ) {
7484 TMapOfNodeSet::iterator& itSE = pp.first;
7485 ind = (*itSE).second;
7486 arrayOfGroups[ind].push_back(curElem->GetID());
7489 groupOfElems.clear();
7490 groupOfElems.push_back(curElem->GetID());
7491 arrayOfGroups.push_back(groupOfElems);
7496 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7497 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7498 groupOfElems = *groupIt;
7499 if ( groupOfElems.size() > 1 ) {
7500 groupOfElems.sort();
7501 theGroupsOfElementsID.push_back(groupOfElems);
7506 //=======================================================================
7507 //function : MergeElements
7508 //purpose : In each given group, substitute all elements by the first one.
7509 //=======================================================================
7511 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7513 myLastCreatedElems.Clear();
7514 myLastCreatedNodes.Clear();
7516 typedef list<int> TListOfIDs;
7517 TListOfIDs rmElemIds; // IDs of elems to remove
7519 SMESHDS_Mesh* aMesh = GetMeshDS();
7521 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7522 while ( groupsIt != theGroupsOfElementsID.end() ) {
7523 TListOfIDs& aGroupOfElemID = *groupsIt;
7524 aGroupOfElemID.sort();
7525 int elemIDToKeep = aGroupOfElemID.front();
7526 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7527 aGroupOfElemID.pop_front();
7528 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7529 while ( idIt != aGroupOfElemID.end() ) {
7530 int elemIDToRemove = *idIt;
7531 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7532 // add the kept element in groups of removed one (PAL15188)
7533 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7534 rmElemIds.push_back( elemIDToRemove );
7540 Remove( rmElemIds, false );
7543 //=======================================================================
7544 //function : MergeEqualElements
7545 //purpose : Remove all but one of elements built on the same nodes.
7546 //=======================================================================
7548 void SMESH_MeshEditor::MergeEqualElements()
7550 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7551 to merge equal elements in the whole mesh */
7552 TListOfListOfElementsID aGroupsOfElementsID;
7553 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7554 MergeElements(aGroupsOfElementsID);
7557 //=======================================================================
7558 //function : FindFaceInSet
7559 //purpose : Return a face having linked nodes n1 and n2 and which is
7560 // - not in avoidSet,
7561 // - in elemSet provided that !elemSet.empty()
7562 // i1 and i2 optionally returns indices of n1 and n2
7563 //=======================================================================
7565 const SMDS_MeshElement*
7566 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7567 const SMDS_MeshNode* n2,
7568 const TIDSortedElemSet& elemSet,
7569 const TIDSortedElemSet& avoidSet,
7575 const SMDS_MeshElement* face = 0;
7577 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7578 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7580 const SMDS_MeshElement* elem = invElemIt->next();
7581 if (avoidSet.count( elem ))
7583 if ( !elemSet.empty() && !elemSet.count( elem ))
7586 i1 = elem->GetNodeIndex( n1 );
7587 // find a n2 linked to n1
7588 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7589 for ( int di = -1; di < 2 && !face; di += 2 )
7591 i2 = (i1+di+nbN) % nbN;
7592 if ( elem->GetNode( i2 ) == n2 )
7595 if ( !face && elem->IsQuadratic())
7597 // analysis for quadratic elements using all nodes
7598 const SMDS_QuadraticFaceOfNodes* F =
7599 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7600 // use special nodes iterator
7601 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7602 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7603 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7605 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7606 if ( n1 == prevN && n2 == n )
7610 else if ( n2 == prevN && n1 == n )
7612 face = elem; swap( i1, i2 );
7618 if ( n1ind ) *n1ind = i1;
7619 if ( n2ind ) *n2ind = i2;
7623 //=======================================================================
7624 //function : findAdjacentFace
7626 //=======================================================================
7628 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7629 const SMDS_MeshNode* n2,
7630 const SMDS_MeshElement* elem)
7632 TIDSortedElemSet elemSet, avoidSet;
7634 avoidSet.insert ( elem );
7635 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7638 //=======================================================================
7639 //function : FindFreeBorder
7641 //=======================================================================
7643 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7645 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7646 const SMDS_MeshNode* theSecondNode,
7647 const SMDS_MeshNode* theLastNode,
7648 list< const SMDS_MeshNode* > & theNodes,
7649 list< const SMDS_MeshElement* >& theFaces)
7651 if ( !theFirstNode || !theSecondNode )
7653 // find border face between theFirstNode and theSecondNode
7654 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7658 theFaces.push_back( curElem );
7659 theNodes.push_back( theFirstNode );
7660 theNodes.push_back( theSecondNode );
7662 //vector<const SMDS_MeshNode*> nodes;
7663 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7664 TIDSortedElemSet foundElems;
7665 bool needTheLast = ( theLastNode != 0 );
7667 while ( nStart != theLastNode ) {
7668 if ( nStart == theFirstNode )
7669 return !needTheLast;
7671 // find all free border faces sharing form nStart
7673 list< const SMDS_MeshElement* > curElemList;
7674 list< const SMDS_MeshNode* > nStartList;
7675 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7676 while ( invElemIt->more() ) {
7677 const SMDS_MeshElement* e = invElemIt->next();
7678 if ( e == curElem || foundElems.insert( e ).second ) {
7680 int iNode = 0, nbNodes = e->NbNodes();
7681 //const SMDS_MeshNode* nodes[nbNodes+1];
7682 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7684 if(e->IsQuadratic()) {
7685 const SMDS_QuadraticFaceOfNodes* F =
7686 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7687 // use special nodes iterator
7688 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7689 while( anIter->more() ) {
7690 nodes[ iNode++ ] = anIter->next();
7694 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7695 while ( nIt->more() )
7696 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7698 nodes[ iNode ] = nodes[ 0 ];
7700 for ( iNode = 0; iNode < nbNodes; iNode++ )
7701 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7702 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7703 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7705 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7706 curElemList.push_back( e );
7710 // analyse the found
7712 int nbNewBorders = curElemList.size();
7713 if ( nbNewBorders == 0 ) {
7714 // no free border furthermore
7715 return !needTheLast;
7717 else if ( nbNewBorders == 1 ) {
7718 // one more element found
7720 nStart = nStartList.front();
7721 curElem = curElemList.front();
7722 theFaces.push_back( curElem );
7723 theNodes.push_back( nStart );
7726 // several continuations found
7727 list< const SMDS_MeshElement* >::iterator curElemIt;
7728 list< const SMDS_MeshNode* >::iterator nStartIt;
7729 // check if one of them reached the last node
7730 if ( needTheLast ) {
7731 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7732 curElemIt!= curElemList.end();
7733 curElemIt++, nStartIt++ )
7734 if ( *nStartIt == theLastNode ) {
7735 theFaces.push_back( *curElemIt );
7736 theNodes.push_back( *nStartIt );
7740 // find the best free border by the continuations
7741 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7742 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7743 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7744 curElemIt!= curElemList.end();
7745 curElemIt++, nStartIt++ )
7747 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7748 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7749 // find one more free border
7750 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7754 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7755 // choice: clear a worse one
7756 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7757 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7758 contNodes[ iWorse ].clear();
7759 contFaces[ iWorse ].clear();
7762 if ( contNodes[0].empty() && contNodes[1].empty() )
7765 // append the best free border
7766 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7767 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7768 theNodes.pop_back(); // remove nIgnore
7769 theNodes.pop_back(); // remove nStart
7770 theFaces.pop_back(); // remove curElem
7771 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7772 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7773 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7774 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7777 } // several continuations found
7778 } // while ( nStart != theLastNode )
7783 //=======================================================================
7784 //function : CheckFreeBorderNodes
7785 //purpose : Return true if the tree nodes are on a free border
7786 //=======================================================================
7788 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7789 const SMDS_MeshNode* theNode2,
7790 const SMDS_MeshNode* theNode3)
7792 list< const SMDS_MeshNode* > nodes;
7793 list< const SMDS_MeshElement* > faces;
7794 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7797 //=======================================================================
7798 //function : SewFreeBorder
7800 //=======================================================================
7802 SMESH_MeshEditor::Sew_Error
7803 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7804 const SMDS_MeshNode* theBordSecondNode,
7805 const SMDS_MeshNode* theBordLastNode,
7806 const SMDS_MeshNode* theSideFirstNode,
7807 const SMDS_MeshNode* theSideSecondNode,
7808 const SMDS_MeshNode* theSideThirdNode,
7809 const bool theSideIsFreeBorder,
7810 const bool toCreatePolygons,
7811 const bool toCreatePolyedrs)
7813 myLastCreatedElems.Clear();
7814 myLastCreatedNodes.Clear();
7816 MESSAGE("::SewFreeBorder()");
7817 Sew_Error aResult = SEW_OK;
7819 // ====================================
7820 // find side nodes and elements
7821 // ====================================
7823 list< const SMDS_MeshNode* > nSide[ 2 ];
7824 list< const SMDS_MeshElement* > eSide[ 2 ];
7825 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7826 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7830 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7831 nSide[0], eSide[0])) {
7832 MESSAGE(" Free Border 1 not found " );
7833 aResult = SEW_BORDER1_NOT_FOUND;
7835 if (theSideIsFreeBorder) {
7838 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7839 nSide[1], eSide[1])) {
7840 MESSAGE(" Free Border 2 not found " );
7841 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7844 if ( aResult != SEW_OK )
7847 if (!theSideIsFreeBorder) {
7851 // -------------------------------------------------------------------------
7853 // 1. If nodes to merge are not coincident, move nodes of the free border
7854 // from the coord sys defined by the direction from the first to last
7855 // nodes of the border to the correspondent sys of the side 2
7856 // 2. On the side 2, find the links most co-directed with the correspondent
7857 // links of the free border
7858 // -------------------------------------------------------------------------
7860 // 1. Since sewing may brake if there are volumes to split on the side 2,
7861 // we wont move nodes but just compute new coordinates for them
7862 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7863 TNodeXYZMap nBordXYZ;
7864 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7865 list< const SMDS_MeshNode* >::iterator nBordIt;
7867 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7868 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7869 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7870 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7871 double tol2 = 1.e-8;
7872 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7873 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7874 // Need node movement.
7876 // find X and Z axes to create trsf
7877 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7879 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7881 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7884 gp_Ax3 toBordAx( Pb1, Zb, X );
7885 gp_Ax3 fromSideAx( Ps1, Zs, X );
7886 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7888 gp_Trsf toBordSys, fromSide2Sys;
7889 toBordSys.SetTransformation( toBordAx );
7890 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7891 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7894 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7895 const SMDS_MeshNode* n = *nBordIt;
7896 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7897 toBordSys.Transforms( xyz );
7898 fromSide2Sys.Transforms( xyz );
7899 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7903 // just insert nodes XYZ in the nBordXYZ map
7904 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7905 const SMDS_MeshNode* n = *nBordIt;
7906 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7910 // 2. On the side 2, find the links most co-directed with the correspondent
7911 // links of the free border
7913 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7914 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7915 sideNodes.push_back( theSideFirstNode );
7917 bool hasVolumes = false;
7918 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7919 set<long> foundSideLinkIDs, checkedLinkIDs;
7920 SMDS_VolumeTool volume;
7921 //const SMDS_MeshNode* faceNodes[ 4 ];
7923 const SMDS_MeshNode* sideNode;
7924 const SMDS_MeshElement* sideElem;
7925 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7926 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7927 nBordIt = bordNodes.begin();
7929 // border node position and border link direction to compare with
7930 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7931 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7932 // choose next side node by link direction or by closeness to
7933 // the current border node:
7934 bool searchByDir = ( *nBordIt != theBordLastNode );
7936 // find the next node on the Side 2
7938 double maxDot = -DBL_MAX, minDist = DBL_MAX;
7940 checkedLinkIDs.clear();
7941 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7943 // loop on inverse elements of current node (prevSideNode) on the Side 2
7944 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7945 while ( invElemIt->more() )
7947 const SMDS_MeshElement* elem = invElemIt->next();
7948 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7949 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7950 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7951 bool isVolume = volume.Set( elem );
7952 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7953 if ( isVolume ) // --volume
7955 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7956 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7957 if(elem->IsQuadratic()) {
7958 const SMDS_QuadraticFaceOfNodes* F =
7959 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7960 // use special nodes iterator
7961 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7962 while( anIter->more() ) {
7963 nodes[ iNode ] = anIter->next();
7964 if ( nodes[ iNode++ ] == prevSideNode )
7965 iPrevNode = iNode - 1;
7969 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7970 while ( nIt->more() ) {
7971 nodes[ iNode ] = cast2Node( nIt->next() );
7972 if ( nodes[ iNode++ ] == prevSideNode )
7973 iPrevNode = iNode - 1;
7976 // there are 2 links to check
7981 // loop on links, to be precise, on the second node of links
7982 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7983 const SMDS_MeshNode* n = nodes[ iNode ];
7985 if ( !volume.IsLinked( n, prevSideNode ))
7989 if ( iNode ) // a node before prevSideNode
7990 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7991 else // a node after prevSideNode
7992 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7994 // check if this link was already used
7995 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7996 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7997 if (!isJustChecked &&
7998 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8000 // test a link geometrically
8001 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8002 bool linkIsBetter = false;
8003 double dot = 0.0, dist = 0.0;
8004 if ( searchByDir ) { // choose most co-directed link
8005 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8006 linkIsBetter = ( dot > maxDot );
8008 else { // choose link with the node closest to bordPos
8009 dist = ( nextXYZ - bordPos ).SquareModulus();
8010 linkIsBetter = ( dist < minDist );
8012 if ( linkIsBetter ) {
8021 } // loop on inverse elements of prevSideNode
8024 MESSAGE(" Cant find path by links of the Side 2 ");
8025 return SEW_BAD_SIDE_NODES;
8027 sideNodes.push_back( sideNode );
8028 sideElems.push_back( sideElem );
8029 foundSideLinkIDs.insert ( linkID );
8030 prevSideNode = sideNode;
8032 if ( *nBordIt == theBordLastNode )
8033 searchByDir = false;
8035 // find the next border link to compare with
8036 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8037 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8038 // move to next border node if sideNode is before forward border node (bordPos)
8039 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8040 prevBordNode = *nBordIt;
8042 bordPos = nBordXYZ[ *nBordIt ];
8043 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8044 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8048 while ( sideNode != theSideSecondNode );
8050 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8051 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8052 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8054 } // end nodes search on the side 2
8056 // ============================
8057 // sew the border to the side 2
8058 // ============================
8060 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8061 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8063 TListOfListOfNodes nodeGroupsToMerge;
8064 if ( nbNodes[0] == nbNodes[1] ||
8065 ( theSideIsFreeBorder && !theSideThirdNode)) {
8067 // all nodes are to be merged
8069 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8070 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8071 nIt[0]++, nIt[1]++ )
8073 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8074 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8075 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8080 // insert new nodes into the border and the side to get equal nb of segments
8082 // get normalized parameters of nodes on the borders
8083 //double param[ 2 ][ maxNbNodes ];
8085 param[0] = new double [ maxNbNodes ];
8086 param[1] = new double [ maxNbNodes ];
8088 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8089 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8090 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8091 const SMDS_MeshNode* nPrev = *nIt;
8092 double bordLength = 0;
8093 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8094 const SMDS_MeshNode* nCur = *nIt;
8095 gp_XYZ segment (nCur->X() - nPrev->X(),
8096 nCur->Y() - nPrev->Y(),
8097 nCur->Z() - nPrev->Z());
8098 double segmentLen = segment.Modulus();
8099 bordLength += segmentLen;
8100 param[ iBord ][ iNode ] = bordLength;
8103 // normalize within [0,1]
8104 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8105 param[ iBord ][ iNode ] /= bordLength;
8109 // loop on border segments
8110 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8111 int i[ 2 ] = { 0, 0 };
8112 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8113 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8115 TElemOfNodeListMap insertMap;
8116 TElemOfNodeListMap::iterator insertMapIt;
8118 // key: elem to insert nodes into
8119 // value: 2 nodes to insert between + nodes to be inserted
8121 bool next[ 2 ] = { false, false };
8123 // find min adjacent segment length after sewing
8124 double nextParam = 10., prevParam = 0;
8125 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8126 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8127 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8128 if ( i[ iBord ] > 0 )
8129 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8131 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8132 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8133 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8135 // choose to insert or to merge nodes
8136 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8137 if ( Abs( du ) <= minSegLen * 0.2 ) {
8140 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8141 const SMDS_MeshNode* n0 = *nIt[0];
8142 const SMDS_MeshNode* n1 = *nIt[1];
8143 nodeGroupsToMerge.back().push_back( n1 );
8144 nodeGroupsToMerge.back().push_back( n0 );
8145 // position of node of the border changes due to merge
8146 param[ 0 ][ i[0] ] += du;
8147 // move n1 for the sake of elem shape evaluation during insertion.
8148 // n1 will be removed by MergeNodes() anyway
8149 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8150 next[0] = next[1] = true;
8155 int intoBord = ( du < 0 ) ? 0 : 1;
8156 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8157 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8158 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8159 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8160 if ( intoBord == 1 ) {
8161 // move node of the border to be on a link of elem of the side
8162 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8163 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8164 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8165 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8166 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8168 insertMapIt = insertMap.find( elem );
8169 bool notFound = ( insertMapIt == insertMap.end() );
8170 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8172 // insert into another link of the same element:
8173 // 1. perform insertion into the other link of the elem
8174 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8175 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8176 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8177 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8178 // 2. perform insertion into the link of adjacent faces
8180 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8182 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8186 if (toCreatePolyedrs) {
8187 // perform insertion into the links of adjacent volumes
8188 UpdateVolumes(n12, n22, nodeList);
8190 // 3. find an element appeared on n1 and n2 after the insertion
8191 insertMap.erase( elem );
8192 elem = findAdjacentFace( n1, n2, 0 );
8194 if ( notFound || otherLink ) {
8195 // add element and nodes of the side into the insertMap
8196 insertMapIt = insertMap.insert
8197 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8198 (*insertMapIt).second.push_back( n1 );
8199 (*insertMapIt).second.push_back( n2 );
8201 // add node to be inserted into elem
8202 (*insertMapIt).second.push_back( nIns );
8203 next[ 1 - intoBord ] = true;
8206 // go to the next segment
8207 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8208 if ( next[ iBord ] ) {
8209 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8211 nPrev[ iBord ] = *nIt[ iBord ];
8212 nIt[ iBord ]++; i[ iBord ]++;
8216 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8218 // perform insertion of nodes into elements
8220 for (insertMapIt = insertMap.begin();
8221 insertMapIt != insertMap.end();
8224 const SMDS_MeshElement* elem = (*insertMapIt).first;
8225 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8226 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8227 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8229 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8231 if ( !theSideIsFreeBorder ) {
8232 // look for and insert nodes into the faces adjacent to elem
8234 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8236 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8241 if (toCreatePolyedrs) {
8242 // perform insertion into the links of adjacent volumes
8243 UpdateVolumes(n1, n2, nodeList);
8249 } // end: insert new nodes
8251 MergeNodes ( nodeGroupsToMerge );
8256 //=======================================================================
8257 //function : InsertNodesIntoLink
8258 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8259 // and theBetweenNode2 and split theElement
8260 //=======================================================================
8262 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8263 const SMDS_MeshNode* theBetweenNode1,
8264 const SMDS_MeshNode* theBetweenNode2,
8265 list<const SMDS_MeshNode*>& theNodesToInsert,
8266 const bool toCreatePoly)
8268 if ( theFace->GetType() != SMDSAbs_Face ) return;
8270 // find indices of 2 link nodes and of the rest nodes
8271 int iNode = 0, il1, il2, i3, i4;
8272 il1 = il2 = i3 = i4 = -1;
8273 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8274 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8276 if(theFace->IsQuadratic()) {
8277 const SMDS_QuadraticFaceOfNodes* F =
8278 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8279 // use special nodes iterator
8280 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8281 while( anIter->more() ) {
8282 const SMDS_MeshNode* n = anIter->next();
8283 if ( n == theBetweenNode1 )
8285 else if ( n == theBetweenNode2 )
8291 nodes[ iNode++ ] = n;
8295 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8296 while ( nodeIt->more() ) {
8297 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8298 if ( n == theBetweenNode1 )
8300 else if ( n == theBetweenNode2 )
8306 nodes[ iNode++ ] = n;
8309 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8312 // arrange link nodes to go one after another regarding the face orientation
8313 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8314 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8319 aNodesToInsert.reverse();
8321 // check that not link nodes of a quadrangles are in good order
8322 int nbFaceNodes = theFace->NbNodes();
8323 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8329 if (toCreatePoly || theFace->IsPoly()) {
8332 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8334 // add nodes of face up to first node of link
8337 if(theFace->IsQuadratic()) {
8338 const SMDS_QuadraticFaceOfNodes* F =
8339 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8340 // use special nodes iterator
8341 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8342 while( anIter->more() && !isFLN ) {
8343 const SMDS_MeshNode* n = anIter->next();
8344 poly_nodes[iNode++] = n;
8345 if (n == nodes[il1]) {
8349 // add nodes to insert
8350 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8351 for (; nIt != aNodesToInsert.end(); nIt++) {
8352 poly_nodes[iNode++] = *nIt;
8354 // add nodes of face starting from last node of link
8355 while ( anIter->more() ) {
8356 poly_nodes[iNode++] = anIter->next();
8360 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8361 while ( nodeIt->more() && !isFLN ) {
8362 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8363 poly_nodes[iNode++] = n;
8364 if (n == nodes[il1]) {
8368 // add nodes to insert
8369 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8370 for (; nIt != aNodesToInsert.end(); nIt++) {
8371 poly_nodes[iNode++] = *nIt;
8373 // add nodes of face starting from last node of link
8374 while ( nodeIt->more() ) {
8375 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8376 poly_nodes[iNode++] = n;
8380 // edit or replace the face
8381 SMESHDS_Mesh *aMesh = GetMeshDS();
8383 if (theFace->IsPoly()) {
8384 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8387 int aShapeId = FindShape( theFace );
8389 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8390 myLastCreatedElems.Append(newElem);
8391 if ( aShapeId && newElem )
8392 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8394 aMesh->RemoveElement(theFace);
8399 if( !theFace->IsQuadratic() ) {
8401 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8402 int nbLinkNodes = 2 + aNodesToInsert.size();
8403 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8404 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8405 linkNodes[ 0 ] = nodes[ il1 ];
8406 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8407 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8408 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8409 linkNodes[ iNode++ ] = *nIt;
8411 // decide how to split a quadrangle: compare possible variants
8412 // and choose which of splits to be a quadrangle
8413 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8414 if ( nbFaceNodes == 3 ) {
8415 iBestQuad = nbSplits;
8418 else if ( nbFaceNodes == 4 ) {
8419 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8420 double aBestRate = DBL_MAX;
8421 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8423 double aBadRate = 0;
8424 // evaluate elements quality
8425 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8426 if ( iSplit == iQuad ) {
8427 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8431 aBadRate += getBadRate( &quad, aCrit );
8434 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8436 nodes[ iSplit < iQuad ? i4 : i3 ]);
8437 aBadRate += getBadRate( &tria, aCrit );
8441 if ( aBadRate < aBestRate ) {
8443 aBestRate = aBadRate;
8448 // create new elements
8449 SMESHDS_Mesh *aMesh = GetMeshDS();
8450 int aShapeId = FindShape( theFace );
8453 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8454 SMDS_MeshElement* newElem = 0;
8455 if ( iSplit == iBestQuad )
8456 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8461 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8463 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8464 myLastCreatedElems.Append(newElem);
8465 if ( aShapeId && newElem )
8466 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8469 // change nodes of theFace
8470 const SMDS_MeshNode* newNodes[ 4 ];
8471 newNodes[ 0 ] = linkNodes[ i1 ];
8472 newNodes[ 1 ] = linkNodes[ i2 ];
8473 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8474 newNodes[ 3 ] = nodes[ i4 ];
8475 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8476 } // end if(!theFace->IsQuadratic())
8477 else { // theFace is quadratic
8478 // we have to split theFace on simple triangles and one simple quadrangle
8480 int nbshift = tmp*2;
8481 // shift nodes in nodes[] by nbshift
8483 for(i=0; i<nbshift; i++) {
8484 const SMDS_MeshNode* n = nodes[0];
8485 for(j=0; j<nbFaceNodes-1; j++) {
8486 nodes[j] = nodes[j+1];
8488 nodes[nbFaceNodes-1] = n;
8490 il1 = il1 - nbshift;
8491 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8492 // n0 n1 n2 n0 n1 n2
8493 // +-----+-----+ +-----+-----+
8502 // create new elements
8503 SMESHDS_Mesh *aMesh = GetMeshDS();
8504 int aShapeId = FindShape( theFace );
8507 if(nbFaceNodes==6) { // quadratic triangle
8508 SMDS_MeshElement* newElem =
8509 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8510 myLastCreatedElems.Append(newElem);
8511 if ( aShapeId && newElem )
8512 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8513 if(theFace->IsMediumNode(nodes[il1])) {
8514 // create quadrangle
8515 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8516 myLastCreatedElems.Append(newElem);
8517 if ( aShapeId && newElem )
8518 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8524 // create quadrangle
8525 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8526 myLastCreatedElems.Append(newElem);
8527 if ( aShapeId && newElem )
8528 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8534 else { // nbFaceNodes==8 - quadratic quadrangle
8535 SMDS_MeshElement* newElem =
8536 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8537 myLastCreatedElems.Append(newElem);
8538 if ( aShapeId && newElem )
8539 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8540 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8541 myLastCreatedElems.Append(newElem);
8542 if ( aShapeId && newElem )
8543 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8544 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8545 myLastCreatedElems.Append(newElem);
8546 if ( aShapeId && newElem )
8547 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8548 if(theFace->IsMediumNode(nodes[il1])) {
8549 // create quadrangle
8550 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8551 myLastCreatedElems.Append(newElem);
8552 if ( aShapeId && newElem )
8553 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8559 // create quadrangle
8560 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8561 myLastCreatedElems.Append(newElem);
8562 if ( aShapeId && newElem )
8563 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8569 // create needed triangles using n1,n2,n3 and inserted nodes
8570 int nbn = 2 + aNodesToInsert.size();
8571 //const SMDS_MeshNode* aNodes[nbn];
8572 vector<const SMDS_MeshNode*> aNodes(nbn);
8573 aNodes[0] = nodes[n1];
8574 aNodes[nbn-1] = nodes[n2];
8575 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8576 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8577 aNodes[iNode++] = *nIt;
8579 for(i=1; i<nbn; i++) {
8580 SMDS_MeshElement* newElem =
8581 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8582 myLastCreatedElems.Append(newElem);
8583 if ( aShapeId && newElem )
8584 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8586 // remove old quadratic face
8587 aMesh->RemoveElement(theFace);
8591 //=======================================================================
8592 //function : UpdateVolumes
8594 //=======================================================================
8595 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8596 const SMDS_MeshNode* theBetweenNode2,
8597 list<const SMDS_MeshNode*>& theNodesToInsert)
8599 myLastCreatedElems.Clear();
8600 myLastCreatedNodes.Clear();
8602 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8603 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8604 const SMDS_MeshElement* elem = invElemIt->next();
8606 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8607 SMDS_VolumeTool aVolume (elem);
8608 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8611 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8612 int iface, nbFaces = aVolume.NbFaces();
8613 vector<const SMDS_MeshNode *> poly_nodes;
8614 vector<int> quantities (nbFaces);
8616 for (iface = 0; iface < nbFaces; iface++) {
8617 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8618 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8619 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8621 for (int inode = 0; inode < nbFaceNodes; inode++) {
8622 poly_nodes.push_back(faceNodes[inode]);
8624 if (nbInserted == 0) {
8625 if (faceNodes[inode] == theBetweenNode1) {
8626 if (faceNodes[inode + 1] == theBetweenNode2) {
8627 nbInserted = theNodesToInsert.size();
8629 // add nodes to insert
8630 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8631 for (; nIt != theNodesToInsert.end(); nIt++) {
8632 poly_nodes.push_back(*nIt);
8636 else if (faceNodes[inode] == theBetweenNode2) {
8637 if (faceNodes[inode + 1] == theBetweenNode1) {
8638 nbInserted = theNodesToInsert.size();
8640 // add nodes to insert in reversed order
8641 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8643 for (; nIt != theNodesToInsert.begin(); nIt--) {
8644 poly_nodes.push_back(*nIt);
8646 poly_nodes.push_back(*nIt);
8653 quantities[iface] = nbFaceNodes + nbInserted;
8656 // Replace or update the volume
8657 SMESHDS_Mesh *aMesh = GetMeshDS();
8659 if (elem->IsPoly()) {
8660 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8664 int aShapeId = FindShape( elem );
8666 SMDS_MeshElement* newElem =
8667 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8668 myLastCreatedElems.Append(newElem);
8669 if (aShapeId && newElem)
8670 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8672 aMesh->RemoveElement(elem);
8677 //=======================================================================
8679 * \brief Convert elements contained in a submesh to quadratic
8680 * \retval int - nb of checked elements
8682 //=======================================================================
8684 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8685 SMESH_MesherHelper& theHelper,
8686 const bool theForce3d)
8689 if( !theSm ) return nbElem;
8691 vector<int> nbNodeInFaces;
8692 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8693 while(ElemItr->more())
8696 const SMDS_MeshElement* elem = ElemItr->next();
8697 if( !elem || elem->IsQuadratic() ) continue;
8699 int id = elem->GetID();
8700 int nbNodes = elem->NbNodes();
8701 SMDSAbs_ElementType aType = elem->GetType();
8703 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
8704 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
8705 nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >( elem )->GetQuanities();
8707 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8709 const SMDS_MeshElement* NewElem = 0;
8715 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8723 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8726 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8729 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8734 case SMDSAbs_Volume :
8739 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8742 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8745 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8748 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8749 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8752 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8759 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8761 theSm->AddElement( NewElem );
8766 //=======================================================================
8767 //function : ConvertToQuadratic
8769 //=======================================================================
8770 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8772 SMESHDS_Mesh* meshDS = GetMeshDS();
8774 SMESH_MesherHelper aHelper(*myMesh);
8775 aHelper.SetIsQuadratic( true );
8777 int nbCheckedElems = 0;
8778 if ( myMesh->HasShapeToMesh() )
8780 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8782 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8783 while ( smIt->more() ) {
8784 SMESH_subMesh* sm = smIt->next();
8785 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8786 aHelper.SetSubShape( sm->GetSubShape() );
8787 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8792 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8793 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8795 SMESHDS_SubMesh *smDS = 0;
8796 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8797 while(aEdgeItr->more())
8799 const SMDS_MeshEdge* edge = aEdgeItr->next();
8800 if(edge && !edge->IsQuadratic())
8802 int id = edge->GetID();
8803 const SMDS_MeshNode* n1 = edge->GetNode(0);
8804 const SMDS_MeshNode* n2 = edge->GetNode(1);
8806 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8808 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8809 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8812 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8813 while(aFaceItr->more())
8815 const SMDS_MeshFace* face = aFaceItr->next();
8816 if(!face || face->IsQuadratic() ) continue;
8818 int id = face->GetID();
8819 int nbNodes = face->NbNodes();
8820 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8822 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8824 SMDS_MeshFace * NewFace = 0;
8828 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8831 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8834 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8836 ReplaceElemInGroups( face, NewFace, GetMeshDS());
8838 vector<int> nbNodeInFaces;
8839 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8840 while(aVolumeItr->more())
8842 const SMDS_MeshVolume* volume = aVolumeItr->next();
8843 if(!volume || volume->IsQuadratic() ) continue;
8845 int id = volume->GetID();
8846 int nbNodes = volume->NbNodes();
8847 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8848 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
8849 nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >(volume)->GetQuanities();
8851 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8853 SMDS_MeshVolume * NewVolume = 0;
8857 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8858 nodes[3], id, theForce3d );
8861 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8862 nodes[3], nodes[4], id, theForce3d);
8865 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8866 nodes[3], nodes[4], nodes[5], id, theForce3d);
8869 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8870 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8873 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8875 ReplaceElemInGroups(volume, NewVolume, meshDS);
8879 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
8880 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8881 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8882 aHelper.FixQuadraticElements();
8886 //=======================================================================
8888 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8889 * \retval int - nb of checked elements
8891 //=======================================================================
8893 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
8894 SMDS_ElemIteratorPtr theItr,
8895 const int theShapeID)
8898 SMESHDS_Mesh* meshDS = GetMeshDS();
8899 const bool notFromGroups = false;
8901 while( theItr->more() )
8903 const SMDS_MeshElement* elem = theItr->next();
8905 if( elem && elem->IsQuadratic())
8907 int id = elem->GetID();
8908 int nbNodes = elem->NbNodes();
8909 vector<const SMDS_MeshNode *> nodes, mediumNodes;
8910 nodes.reserve( nbNodes );
8911 mediumNodes.reserve( nbNodes );
8913 for(int i = 0; i < nbNodes; i++)
8915 const SMDS_MeshNode* n = elem->GetNode(i);
8917 if( elem->IsMediumNode( n ) )
8918 mediumNodes.push_back( n );
8920 nodes.push_back( n );
8922 if( nodes.empty() ) continue;
8923 SMDSAbs_ElementType aType = elem->GetType();
8925 //remove old quadratic element
8926 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8928 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
8929 ReplaceElemInGroups(elem, NewElem, meshDS);
8930 if( theSm && NewElem )
8931 theSm->AddElement( NewElem );
8933 // remove medium nodes
8934 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8935 for ( ; nIt != mediumNodes.end(); ++nIt ) {
8936 const SMDS_MeshNode* n = *nIt;
8937 if ( n->NbInverseElements() == 0 ) {
8938 if ( n->GetPosition()->GetShapeId() != theShapeID )
8939 meshDS->RemoveFreeNode( n, meshDS->MeshElements
8940 ( n->GetPosition()->GetShapeId() ));
8942 meshDS->RemoveFreeNode( n, theSm );
8950 //=======================================================================
8951 //function : ConvertFromQuadratic
8953 //=======================================================================
8954 bool SMESH_MeshEditor::ConvertFromQuadratic()
8956 int nbCheckedElems = 0;
8957 if ( myMesh->HasShapeToMesh() )
8959 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8961 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8962 while ( smIt->more() ) {
8963 SMESH_subMesh* sm = smIt->next();
8964 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8965 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8971 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8972 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8974 SMESHDS_SubMesh *aSM = 0;
8975 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8981 //=======================================================================
8982 //function : SewSideElements
8984 //=======================================================================
8986 SMESH_MeshEditor::Sew_Error
8987 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
8988 TIDSortedElemSet& theSide2,
8989 const SMDS_MeshNode* theFirstNode1,
8990 const SMDS_MeshNode* theFirstNode2,
8991 const SMDS_MeshNode* theSecondNode1,
8992 const SMDS_MeshNode* theSecondNode2)
8994 myLastCreatedElems.Clear();
8995 myLastCreatedNodes.Clear();
8997 MESSAGE ("::::SewSideElements()");
8998 if ( theSide1.size() != theSide2.size() )
8999 return SEW_DIFF_NB_OF_ELEMENTS;
9001 Sew_Error aResult = SEW_OK;
9003 // 1. Build set of faces representing each side
9004 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9005 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9007 // =======================================================================
9008 // 1. Build set of faces representing each side:
9009 // =======================================================================
9010 // a. build set of nodes belonging to faces
9011 // b. complete set of faces: find missing fices whose nodes are in set of nodes
9012 // c. create temporary faces representing side of volumes if correspondent
9013 // face does not exist
9015 SMESHDS_Mesh* aMesh = GetMeshDS();
9016 SMDS_Mesh aTmpFacesMesh;
9017 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9018 set<const SMDS_MeshElement*> volSet1, volSet2;
9019 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9020 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9021 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9022 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9023 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9024 int iSide, iFace, iNode;
9026 for ( iSide = 0; iSide < 2; iSide++ ) {
9027 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9028 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9029 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9030 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9031 set<const SMDS_MeshElement*>::iterator vIt;
9032 TIDSortedElemSet::iterator eIt;
9033 set<const SMDS_MeshNode*>::iterator nIt;
9035 // check that given nodes belong to given elements
9036 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9037 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9038 int firstIndex = -1, secondIndex = -1;
9039 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9040 const SMDS_MeshElement* elem = *eIt;
9041 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9042 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9043 if ( firstIndex > -1 && secondIndex > -1 ) break;
9045 if ( firstIndex < 0 || secondIndex < 0 ) {
9046 // we can simply return until temporary faces created
9047 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9050 // -----------------------------------------------------------
9051 // 1a. Collect nodes of existing faces
9052 // and build set of face nodes in order to detect missing
9053 // faces corresponing to sides of volumes
9054 // -----------------------------------------------------------
9056 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9058 // loop on the given element of a side
9059 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9060 //const SMDS_MeshElement* elem = *eIt;
9061 const SMDS_MeshElement* elem = *eIt;
9062 if ( elem->GetType() == SMDSAbs_Face ) {
9063 faceSet->insert( elem );
9064 set <const SMDS_MeshNode*> faceNodeSet;
9065 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9066 while ( nodeIt->more() ) {
9067 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9068 nodeSet->insert( n );
9069 faceNodeSet.insert( n );
9071 setOfFaceNodeSet.insert( faceNodeSet );
9073 else if ( elem->GetType() == SMDSAbs_Volume )
9074 volSet->insert( elem );
9076 // ------------------------------------------------------------------------------
9077 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9078 // ------------------------------------------------------------------------------
9080 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9081 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9082 while ( fIt->more() ) { // loop on faces sharing a node
9083 const SMDS_MeshElement* f = fIt->next();
9084 if ( faceSet->find( f ) == faceSet->end() ) {
9085 // check if all nodes are in nodeSet and
9086 // complete setOfFaceNodeSet if they are
9087 set <const SMDS_MeshNode*> faceNodeSet;
9088 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9089 bool allInSet = true;
9090 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9091 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9092 if ( nodeSet->find( n ) == nodeSet->end() )
9095 faceNodeSet.insert( n );
9098 faceSet->insert( f );
9099 setOfFaceNodeSet.insert( faceNodeSet );
9105 // -------------------------------------------------------------------------
9106 // 1c. Create temporary faces representing sides of volumes if correspondent
9107 // face does not exist
9108 // -------------------------------------------------------------------------
9110 if ( !volSet->empty() ) {
9111 //int nodeSetSize = nodeSet->size();
9113 // loop on given volumes
9114 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9115 SMDS_VolumeTool vol (*vIt);
9116 // loop on volume faces: find free faces
9117 // --------------------------------------
9118 list<const SMDS_MeshElement* > freeFaceList;
9119 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9120 if ( !vol.IsFreeFace( iFace ))
9122 // check if there is already a face with same nodes in a face set
9123 const SMDS_MeshElement* aFreeFace = 0;
9124 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9125 int nbNodes = vol.NbFaceNodes( iFace );
9126 set <const SMDS_MeshNode*> faceNodeSet;
9127 vol.GetFaceNodes( iFace, faceNodeSet );
9128 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9130 // no such a face is given but it still can exist, check it
9131 if ( nbNodes == 3 ) {
9132 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9134 else if ( nbNodes == 4 ) {
9135 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9138 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9139 aFreeFace = aMesh->FindFace(poly_nodes);
9143 // create a temporary face
9144 if ( nbNodes == 3 ) {
9145 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9147 else if ( nbNodes == 4 ) {
9148 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9151 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9152 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9156 freeFaceList.push_back( aFreeFace );
9158 } // loop on faces of a volume
9160 // choose one of several free faces
9161 // --------------------------------------
9162 if ( freeFaceList.size() > 1 ) {
9163 // choose a face having max nb of nodes shared by other elems of a side
9164 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9165 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9166 while ( fIt != freeFaceList.end() ) { // loop on free faces
9167 int nbSharedNodes = 0;
9168 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9169 while ( nodeIt->more() ) { // loop on free face nodes
9170 const SMDS_MeshNode* n =
9171 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9172 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9173 while ( invElemIt->more() ) {
9174 const SMDS_MeshElement* e = invElemIt->next();
9175 if ( faceSet->find( e ) != faceSet->end() )
9177 if ( elemSet->find( e ) != elemSet->end() )
9181 if ( nbSharedNodes >= maxNbNodes ) {
9182 maxNbNodes = nbSharedNodes;
9186 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9188 if ( freeFaceList.size() > 1 )
9190 // could not choose one face, use another way
9191 // choose a face most close to the bary center of the opposite side
9192 gp_XYZ aBC( 0., 0., 0. );
9193 set <const SMDS_MeshNode*> addedNodes;
9194 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9195 eIt = elemSet2->begin();
9196 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9197 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9198 while ( nodeIt->more() ) { // loop on free face nodes
9199 const SMDS_MeshNode* n =
9200 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9201 if ( addedNodes.insert( n ).second )
9202 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9205 aBC /= addedNodes.size();
9206 double minDist = DBL_MAX;
9207 fIt = freeFaceList.begin();
9208 while ( fIt != freeFaceList.end() ) { // loop on free faces
9210 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9211 while ( nodeIt->more() ) { // loop on free face nodes
9212 const SMDS_MeshNode* n =
9213 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9214 gp_XYZ p( n->X(),n->Y(),n->Z() );
9215 dist += ( aBC - p ).SquareModulus();
9217 if ( dist < minDist ) {
9219 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9222 fIt = freeFaceList.erase( fIt++ );
9225 } // choose one of several free faces of a volume
9227 if ( freeFaceList.size() == 1 ) {
9228 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9229 faceSet->insert( aFreeFace );
9230 // complete a node set with nodes of a found free face
9231 // for ( iNode = 0; iNode < ; iNode++ )
9232 // nodeSet->insert( fNodes[ iNode ] );
9235 } // loop on volumes of a side
9237 // // complete a set of faces if new nodes in a nodeSet appeared
9238 // // ----------------------------------------------------------
9239 // if ( nodeSetSize != nodeSet->size() ) {
9240 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9241 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9242 // while ( fIt->more() ) { // loop on faces sharing a node
9243 // const SMDS_MeshElement* f = fIt->next();
9244 // if ( faceSet->find( f ) == faceSet->end() ) {
9245 // // check if all nodes are in nodeSet and
9246 // // complete setOfFaceNodeSet if they are
9247 // set <const SMDS_MeshNode*> faceNodeSet;
9248 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9249 // bool allInSet = true;
9250 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9251 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9252 // if ( nodeSet->find( n ) == nodeSet->end() )
9253 // allInSet = false;
9255 // faceNodeSet.insert( n );
9257 // if ( allInSet ) {
9258 // faceSet->insert( f );
9259 // setOfFaceNodeSet.insert( faceNodeSet );
9265 } // Create temporary faces, if there are volumes given
9268 if ( faceSet1.size() != faceSet2.size() ) {
9269 // delete temporary faces: they are in reverseElements of actual nodes
9270 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9271 while ( tmpFaceIt->more() )
9272 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9273 MESSAGE("Diff nb of faces");
9274 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9277 // ============================================================
9278 // 2. Find nodes to merge:
9279 // bind a node to remove to a node to put instead
9280 // ============================================================
9282 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9283 if ( theFirstNode1 != theFirstNode2 )
9284 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9285 if ( theSecondNode1 != theSecondNode2 )
9286 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9288 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9289 set< long > linkIdSet; // links to process
9290 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9292 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9293 list< NLink > linkList[2];
9294 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9295 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9296 // loop on links in linkList; find faces by links and append links
9297 // of the found faces to linkList
9298 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9299 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9300 NLink link[] = { *linkIt[0], *linkIt[1] };
9301 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9302 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9305 // by links, find faces in the face sets,
9306 // and find indices of link nodes in the found faces;
9307 // in a face set, there is only one or no face sharing a link
9308 // ---------------------------------------------------------------
9310 const SMDS_MeshElement* face[] = { 0, 0 };
9311 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9312 vector<const SMDS_MeshNode*> fnodes1(9);
9313 vector<const SMDS_MeshNode*> fnodes2(9);
9314 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9315 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9316 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9317 int iLinkNode[2][2];
9318 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9319 const SMDS_MeshNode* n1 = link[iSide].first;
9320 const SMDS_MeshNode* n2 = link[iSide].second;
9321 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9322 set< const SMDS_MeshElement* > fMap;
9323 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9324 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9325 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9326 while ( fIt->more() ) { // loop on faces sharing a node
9327 const SMDS_MeshElement* f = fIt->next();
9328 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9329 ! fMap.insert( f ).second ) // f encounters twice
9331 if ( face[ iSide ] ) {
9332 MESSAGE( "2 faces per link " );
9333 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9337 faceSet->erase( f );
9338 // get face nodes and find ones of a link
9343 fnodes1.resize(f->NbNodes()+1);
9344 notLinkNodes1.resize(f->NbNodes()-2);
9347 fnodes2.resize(f->NbNodes()+1);
9348 notLinkNodes2.resize(f->NbNodes()-2);
9351 if(!f->IsQuadratic()) {
9352 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9353 while ( nIt->more() ) {
9354 const SMDS_MeshNode* n =
9355 static_cast<const SMDS_MeshNode*>( nIt->next() );
9357 iLinkNode[ iSide ][ 0 ] = iNode;
9359 else if ( n == n2 ) {
9360 iLinkNode[ iSide ][ 1 ] = iNode;
9362 //else if ( notLinkNodes[ iSide ][ 0 ] )
9363 // notLinkNodes[ iSide ][ 1 ] = n;
9365 // notLinkNodes[ iSide ][ 0 ] = n;
9369 notLinkNodes1[nbl] = n;
9370 //notLinkNodes1.push_back(n);
9372 notLinkNodes2[nbl] = n;
9373 //notLinkNodes2.push_back(n);
9375 //faceNodes[ iSide ][ iNode++ ] = n;
9377 fnodes1[iNode++] = n;
9380 fnodes2[iNode++] = n;
9384 else { // f->IsQuadratic()
9385 const SMDS_QuadraticFaceOfNodes* F =
9386 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9387 // use special nodes iterator
9388 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9389 while ( anIter->more() ) {
9390 const SMDS_MeshNode* n =
9391 static_cast<const SMDS_MeshNode*>( anIter->next() );
9393 iLinkNode[ iSide ][ 0 ] = iNode;
9395 else if ( n == n2 ) {
9396 iLinkNode[ iSide ][ 1 ] = iNode;
9401 notLinkNodes1[nbl] = n;
9404 notLinkNodes2[nbl] = n;
9408 fnodes1[iNode++] = n;
9411 fnodes2[iNode++] = n;
9415 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9417 fnodes1[iNode] = fnodes1[0];
9420 fnodes2[iNode] = fnodes1[0];
9427 // check similarity of elements of the sides
9428 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9429 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9430 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9431 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9434 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9436 break; // do not return because it s necessary to remove tmp faces
9439 // set nodes to merge
9440 // -------------------
9442 if ( face[0] && face[1] ) {
9443 int nbNodes = face[0]->NbNodes();
9444 if ( nbNodes != face[1]->NbNodes() ) {
9445 MESSAGE("Diff nb of face nodes");
9446 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9447 break; // do not return because it s necessary to remove tmp faces
9449 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9450 if ( nbNodes == 3 ) {
9451 //nReplaceMap.insert( TNodeNodeMap::value_type
9452 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9453 nReplaceMap.insert( TNodeNodeMap::value_type
9454 ( notLinkNodes1[0], notLinkNodes2[0] ));
9457 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9458 // analyse link orientation in faces
9459 int i1 = iLinkNode[ iSide ][ 0 ];
9460 int i2 = iLinkNode[ iSide ][ 1 ];
9461 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9462 // if notLinkNodes are the first and the last ones, then
9463 // their order does not correspond to the link orientation
9464 if (( i1 == 1 && i2 == 2 ) ||
9465 ( i1 == 2 && i2 == 1 ))
9466 reverse[ iSide ] = !reverse[ iSide ];
9468 if ( reverse[0] == reverse[1] ) {
9469 //nReplaceMap.insert( TNodeNodeMap::value_type
9470 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9471 //nReplaceMap.insert( TNodeNodeMap::value_type
9472 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9473 for(int nn=0; nn<nbNodes-2; nn++) {
9474 nReplaceMap.insert( TNodeNodeMap::value_type
9475 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9479 //nReplaceMap.insert( TNodeNodeMap::value_type
9480 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9481 //nReplaceMap.insert( TNodeNodeMap::value_type
9482 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9483 for(int nn=0; nn<nbNodes-2; nn++) {
9484 nReplaceMap.insert( TNodeNodeMap::value_type
9485 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9490 // add other links of the faces to linkList
9491 // -----------------------------------------
9493 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9494 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9495 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9496 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9497 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9498 if ( !iter_isnew.second ) { // already in a set: no need to process
9499 linkIdSet.erase( iter_isnew.first );
9501 else // new in set == encountered for the first time: add
9503 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9504 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9505 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9506 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9507 linkList[0].push_back ( NLink( n1, n2 ));
9508 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9512 } // loop on link lists
9514 if ( aResult == SEW_OK &&
9515 ( linkIt[0] != linkList[0].end() ||
9516 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9517 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9518 " " << (faceSetPtr[1]->empty()));
9519 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9522 // ====================================================================
9523 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9524 // ====================================================================
9526 // delete temporary faces: they are in reverseElements of actual nodes
9527 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9528 while ( tmpFaceIt->more() )
9529 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9531 if ( aResult != SEW_OK)
9534 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9535 // loop on nodes replacement map
9536 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9537 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9538 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9539 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9540 nodeIDsToRemove.push_back( nToRemove->GetID() );
9541 // loop on elements sharing nToRemove
9542 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9543 while ( invElemIt->more() ) {
9544 const SMDS_MeshElement* e = invElemIt->next();
9545 // get a new suite of nodes: make replacement
9546 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9547 vector< const SMDS_MeshNode*> nodes( nbNodes );
9548 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9549 while ( nIt->more() ) {
9550 const SMDS_MeshNode* n =
9551 static_cast<const SMDS_MeshNode*>( nIt->next() );
9552 nnIt = nReplaceMap.find( n );
9553 if ( nnIt != nReplaceMap.end() ) {
9559 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9560 // elemIDsToRemove.push_back( e->GetID() );
9563 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9567 Remove( nodeIDsToRemove, true );
9572 //================================================================================
9574 * \brief Find corresponding nodes in two sets of faces
9575 * \param theSide1 - first face set
9576 * \param theSide2 - second first face
9577 * \param theFirstNode1 - a boundary node of set 1
9578 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9579 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9580 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9581 * \param nReplaceMap - output map of corresponding nodes
9582 * \retval bool - is a success or not
9584 //================================================================================
9587 //#define DEBUG_MATCHING_NODES
9590 SMESH_MeshEditor::Sew_Error
9591 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9592 set<const SMDS_MeshElement*>& theSide2,
9593 const SMDS_MeshNode* theFirstNode1,
9594 const SMDS_MeshNode* theFirstNode2,
9595 const SMDS_MeshNode* theSecondNode1,
9596 const SMDS_MeshNode* theSecondNode2,
9597 TNodeNodeMap & nReplaceMap)
9599 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9601 nReplaceMap.clear();
9602 if ( theFirstNode1 != theFirstNode2 )
9603 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9604 if ( theSecondNode1 != theSecondNode2 )
9605 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9607 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9608 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9610 list< NLink > linkList[2];
9611 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9612 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9614 // loop on links in linkList; find faces by links and append links
9615 // of the found faces to linkList
9616 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9617 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9618 NLink link[] = { *linkIt[0], *linkIt[1] };
9619 if ( linkSet.find( link[0] ) == linkSet.end() )
9622 // by links, find faces in the face sets,
9623 // and find indices of link nodes in the found faces;
9624 // in a face set, there is only one or no face sharing a link
9625 // ---------------------------------------------------------------
9627 const SMDS_MeshElement* face[] = { 0, 0 };
9628 list<const SMDS_MeshNode*> notLinkNodes[2];
9629 //bool reverse[] = { false, false }; // order of notLinkNodes
9631 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9633 const SMDS_MeshNode* n1 = link[iSide].first;
9634 const SMDS_MeshNode* n2 = link[iSide].second;
9635 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9636 set< const SMDS_MeshElement* > facesOfNode1;
9637 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9639 // during a loop of the first node, we find all faces around n1,
9640 // during a loop of the second node, we find one face sharing both n1 and n2
9641 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9642 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9643 while ( fIt->more() ) { // loop on faces sharing a node
9644 const SMDS_MeshElement* f = fIt->next();
9645 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9646 ! facesOfNode1.insert( f ).second ) // f encounters twice
9648 if ( face[ iSide ] ) {
9649 MESSAGE( "2 faces per link " );
9650 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9653 faceSet->erase( f );
9655 // get not link nodes
9656 int nbN = f->NbNodes();
9657 if ( f->IsQuadratic() )
9659 nbNodes[ iSide ] = nbN;
9660 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9661 int i1 = f->GetNodeIndex( n1 );
9662 int i2 = f->GetNodeIndex( n2 );
9663 int iEnd = nbN, iBeg = -1, iDelta = 1;
9664 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9666 std::swap( iEnd, iBeg ); iDelta = -1;
9671 if ( i == iEnd ) i = iBeg + iDelta;
9672 if ( i == i1 ) break;
9673 nodes.push_back ( f->GetNode( i ) );
9679 // check similarity of elements of the sides
9680 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9681 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9682 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9683 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9686 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9690 // set nodes to merge
9691 // -------------------
9693 if ( face[0] && face[1] ) {
9694 if ( nbNodes[0] != nbNodes[1] ) {
9695 MESSAGE("Diff nb of face nodes");
9696 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9698 #ifdef DEBUG_MATCHING_NODES
9699 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9700 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9701 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9703 int nbN = nbNodes[0];
9705 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9706 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9707 for ( int i = 0 ; i < nbN - 2; ++i ) {
9708 #ifdef DEBUG_MATCHING_NODES
9709 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9711 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9715 // add other links of the face 1 to linkList
9716 // -----------------------------------------
9718 const SMDS_MeshElement* f0 = face[0];
9719 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9720 for ( int i = 0; i < nbN; i++ )
9722 const SMDS_MeshNode* n2 = f0->GetNode( i );
9723 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9724 linkSet.insert( SMESH_TLink( n1, n2 ));
9725 if ( !iter_isnew.second ) { // already in a set: no need to process
9726 linkSet.erase( iter_isnew.first );
9728 else // new in set == encountered for the first time: add
9730 #ifdef DEBUG_MATCHING_NODES
9731 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9732 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9734 linkList[0].push_back ( NLink( n1, n2 ));
9735 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9740 } // loop on link lists
9745 //================================================================================
9747 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9748 \param theElems - the list of elements (edges or faces) to be replicated
9749 The nodes for duplication could be found from these elements
9750 \param theNodesNot - list of nodes to NOT replicate
9751 \param theAffectedElems - the list of elements (cells and edges) to which the
9752 replicated nodes should be associated to.
9753 \return TRUE if operation has been completed successfully, FALSE otherwise
9755 //================================================================================
9757 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9758 const TIDSortedElemSet& theNodesNot,
9759 const TIDSortedElemSet& theAffectedElems )
9761 myLastCreatedElems.Clear();
9762 myLastCreatedNodes.Clear();
9764 if ( theElems.size() == 0 )
9767 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9772 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9773 // duplicate elements and nodes
9774 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9775 // replce nodes by duplications
9776 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9780 //================================================================================
9782 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9783 \param theMeshDS - mesh instance
9784 \param theElems - the elements replicated or modified (nodes should be changed)
9785 \param theNodesNot - nodes to NOT replicate
9786 \param theNodeNodeMap - relation of old node to new created node
9787 \param theIsDoubleElem - flag os to replicate element or modify
9788 \return TRUE if operation has been completed successfully, FALSE otherwise
9790 //================================================================================
9792 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9793 const TIDSortedElemSet& theElems,
9794 const TIDSortedElemSet& theNodesNot,
9795 std::map< const SMDS_MeshNode*,
9796 const SMDS_MeshNode* >& theNodeNodeMap,
9797 const bool theIsDoubleElem )
9799 // iterate on through element and duplicate them (by nodes duplication)
9801 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9802 for ( ; elemItr != theElems.end(); ++elemItr )
9804 const SMDS_MeshElement* anElem = *elemItr;
9808 bool isDuplicate = false;
9809 // duplicate nodes to duplicate element
9810 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9811 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9813 while ( anIter->more() )
9816 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9817 SMDS_MeshNode* aNewNode = aCurrNode;
9818 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9819 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9820 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9823 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9824 theNodeNodeMap[ aCurrNode ] = aNewNode;
9825 myLastCreatedNodes.Append( aNewNode );
9827 isDuplicate |= (aCurrNode != aNewNode);
9828 newNodes[ ind++ ] = aNewNode;
9833 if ( theIsDoubleElem )
9834 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9836 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9843 //================================================================================
9845 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9846 \param theNodes - identifiers of nodes to be doubled
9847 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9848 nodes. If list of element identifiers is empty then nodes are doubled but
9849 they not assigned to elements
9850 \return TRUE if operation has been completed successfully, FALSE otherwise
9852 //================================================================================
9854 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9855 const std::list< int >& theListOfModifiedElems )
9857 myLastCreatedElems.Clear();
9858 myLastCreatedNodes.Clear();
9860 if ( theListOfNodes.size() == 0 )
9863 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9867 // iterate through nodes and duplicate them
9869 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9871 std::list< int >::const_iterator aNodeIter;
9872 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9874 int aCurr = *aNodeIter;
9875 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9881 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9884 anOldNodeToNewNode[ aNode ] = aNewNode;
9885 myLastCreatedNodes.Append( aNewNode );
9889 // Create map of new nodes for modified elements
9891 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9893 std::list< int >::const_iterator anElemIter;
9894 for ( anElemIter = theListOfModifiedElems.begin();
9895 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9897 int aCurr = *anElemIter;
9898 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9902 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9904 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9906 while ( anIter->more() )
9908 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9909 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9911 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9912 aNodeArr[ ind++ ] = aNewNode;
9915 aNodeArr[ ind++ ] = aCurrNode;
9917 anElemToNodes[ anElem ] = aNodeArr;
9920 // Change nodes of elements
9922 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9923 anElemToNodesIter = anElemToNodes.begin();
9924 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9926 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9927 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9929 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9937 //================================================================================
9939 \brief Check if element located inside shape
9940 \return TRUE if IN or ON shape, FALSE otherwise
9942 //================================================================================
9944 template<class Classifier>
9945 bool isInside(const SMDS_MeshElement* theElem,
9946 Classifier& theClassifier,
9947 const double theTol)
9949 gp_XYZ centerXYZ (0, 0, 0);
9950 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9951 while (aNodeItr->more())
9952 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9954 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9955 theClassifier.Perform(aPnt, theTol);
9956 TopAbs_State aState = theClassifier.State();
9957 return (aState == TopAbs_IN || aState == TopAbs_ON );
9960 //================================================================================
9962 * \brief Classifier of the 3D point on the TopoDS_Face
9963 * with interaface suitable for isInside()
9965 //================================================================================
9967 struct _FaceClassifier
9969 Extrema_ExtPS _extremum;
9970 BRepAdaptor_Surface _surface;
9971 TopAbs_State _state;
9973 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9975 _extremum.Initialize( _surface,
9976 _surface.FirstUParameter(), _surface.LastUParameter(),
9977 _surface.FirstVParameter(), _surface.LastVParameter(),
9978 _surface.Tolerance(), _surface.Tolerance() );
9980 void Perform(const gp_Pnt& aPnt, double theTol)
9982 _state = TopAbs_OUT;
9983 _extremum.Perform(aPnt);
9984 if ( _extremum.IsDone() )
9985 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9986 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9988 TopAbs_State State() const
9995 //================================================================================
9997 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9998 \param theElems - group of of elements (edges or faces) to be replicated
9999 \param theNodesNot - group of nodes not to replicate
10000 \param theShape - shape to detect affected elements (element which geometric center
10001 located on or inside shape).
10002 The replicated nodes should be associated to affected elements.
10003 \return TRUE if operation has been completed successfully, FALSE otherwise
10005 //================================================================================
10007 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10008 const TIDSortedElemSet& theNodesNot,
10009 const TopoDS_Shape& theShape )
10011 if ( theShape.IsNull() )
10014 const double aTol = Precision::Confusion();
10015 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10016 auto_ptr<_FaceClassifier> aFaceClassifier;
10017 if ( theShape.ShapeType() == TopAbs_SOLID )
10019 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10020 bsc3d->PerformInfinitePoint(aTol);
10022 else if (theShape.ShapeType() == TopAbs_FACE )
10024 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10027 // iterates on indicated elements and get elements by back references from their nodes
10028 TIDSortedElemSet anAffected;
10029 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10030 for ( ; elemItr != theElems.end(); ++elemItr )
10032 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10036 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10037 while ( nodeItr->more() )
10039 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10040 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10042 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10043 while ( backElemItr->more() )
10045 const SMDS_MeshElement* curElem = backElemItr->next();
10046 if ( curElem && theElems.find(curElem) == theElems.end() &&
10048 isInside( curElem, *bsc3d, aTol ) :
10049 isInside( curElem, *aFaceClassifier, aTol )))
10050 anAffected.insert( curElem );
10054 return DoubleNodes( theElems, theNodesNot, anAffected );
10057 //================================================================================
10059 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10060 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10061 * \return TRUE if operation has been completed successfully, FALSE otherwise
10063 //================================================================================
10065 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10067 // iterates on volume elements and detect all free faces on them
10068 SMESHDS_Mesh* aMesh = GetMeshDS();
10071 //bool res = false;
10072 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10073 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10076 const SMDS_MeshVolume* volume = vIt->next();
10077 SMDS_VolumeTool vTool( volume );
10078 vTool.SetExternalNormal();
10079 const bool isPoly = volume->IsPoly();
10080 const bool isQuad = volume->IsQuadratic();
10081 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10083 if (!vTool.IsFreeFace(iface))
10086 vector<const SMDS_MeshNode *> nodes;
10087 int nbFaceNodes = vTool.NbFaceNodes(iface);
10088 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10090 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10091 nodes.push_back(faceNodes[inode]);
10093 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10094 nodes.push_back(faceNodes[inode]);
10096 // add new face based on volume nodes
10097 if (aMesh->FindFace( nodes ) ) {
10099 continue; // face already exsist
10101 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10105 return ( nbFree==(nbExisted+nbCreated) );
10110 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10112 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10114 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10117 //================================================================================
10119 * \brief Creates missing boundary elements
10120 * \param elements - elements whose boundary is to be checked
10121 * \param dimension - defines type of boundary elements to create
10122 * \param group - a group to store created boundary elements in
10123 * \param targetMesh - a mesh to store created boundary elements in
10124 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10125 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10126 * boundary elements will be copied into the targetMesh
10128 //================================================================================
10130 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10131 Bnd_Dimension dimension,
10132 SMESH_Group* group/*=0*/,
10133 SMESH_Mesh* targetMesh/*=0*/,
10134 bool toCopyElements/*=false*/,
10135 bool toCopyExistingBondary/*=false*/)
10137 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10138 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10139 // hope that all elements are of the same type, do not check them all
10140 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10141 throw SALOME_Exception(LOCALIZED("wrong element type"));
10144 toCopyElements = toCopyExistingBondary = false;
10146 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10147 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10149 SMDS_VolumeTool vTool;
10150 TIDSortedElemSet emptySet, avoidSet;
10153 typedef vector<const SMDS_MeshNode*> TConnectivity;
10155 SMDS_ElemIteratorPtr eIt;
10156 if (elements.empty())
10157 eIt = aMesh->elementsIterator(elemType);
10159 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10161 while (eIt->more())
10163 const SMDS_MeshElement* elem = eIt->next();
10164 const int iQuad = elem->IsQuadratic();
10166 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10167 vector<const SMDS_MeshElement*> presentBndElems;
10168 vector<TConnectivity> missingBndElems;
10169 TConnectivity nodes;
10170 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10172 vTool.SetExternalNormal();
10173 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10175 if (!vTool.IsFreeFace(iface))
10177 int nbFaceNodes = vTool.NbFaceNodes(iface);
10178 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10179 if ( missType == SMDSAbs_Edge ) // boundary edges
10181 nodes.resize( 2+iQuad );
10182 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10184 for ( int j = 0; j < nodes.size(); ++j )
10186 if ( const SMDS_MeshElement* edge =
10187 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10188 presentBndElems.push_back( edge );
10190 missingBndElems.push_back( nodes );
10193 else // boundary face
10196 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10197 nodes.push_back( nn[inode] );
10199 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10200 nodes.push_back( nn[inode] );
10202 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10203 presentBndElems.push_back( f );
10205 missingBndElems.push_back( nodes );
10209 else // elem is a face ------------------------------------------
10211 avoidSet.clear(), avoidSet.insert( elem );
10212 int nbNodes = elem->NbCornerNodes();
10213 nodes.resize( 2 /*+ iQuad*/);
10214 for ( int i = 0; i < nbNodes; i++ )
10216 nodes[0] = elem->GetNode(i);
10217 nodes[1] = elem->GetNode((i+1)%nbNodes);
10218 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10219 continue; // not free link
10222 //nodes[2] = elem->GetNode( i + nbNodes );
10223 if ( const SMDS_MeshElement* edge =
10224 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10225 presentBndElems.push_back( edge );
10227 missingBndElems.push_back( nodes );
10231 // 2. Add missing boundary elements
10232 if ( targetMesh != myMesh )
10233 // instead of making a map of nodes in this mesh and targetMesh,
10234 // we create nodes with same IDs. We can renumber them later, if needed
10235 for ( int i = 0; i < missingBndElems.size(); ++i )
10237 TConnectivity& srcNodes = missingBndElems[i];
10238 TConnectivity nodes( srcNodes.size() );
10239 for ( inode = 0; inode < nodes.size(); ++inode )
10240 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10241 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10244 for ( int i = 0; i < missingBndElems.size(); ++i )
10246 TConnectivity& nodes = missingBndElems[i];
10247 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10250 // 3. Copy present boundary elements
10251 if ( toCopyExistingBondary )
10252 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10254 const SMDS_MeshElement* e = presentBndElems[i];
10255 TConnectivity nodes( e->NbNodes() );
10256 for ( inode = 0; inode < nodes.size(); ++inode )
10257 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10258 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10259 // leave only missing elements in tgtEditor.myLastCreatedElems
10260 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10262 } // loop on given elements
10264 // 4. Fill group with missing boundary elements
10267 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10268 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10269 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10271 tgtEditor.myLastCreatedElems.Clear();
10273 // 5. Copy given elements
10274 if ( toCopyElements )
10276 if (elements.empty())
10277 eIt = aMesh->elementsIterator(elemType);
10279 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10280 while (eIt->more())
10282 const SMDS_MeshElement* elem = eIt->next();
10283 TConnectivity nodes( elem->NbNodes() );
10284 for ( inode = 0; inode < nodes.size(); ++inode )
10285 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10286 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10288 tgtEditor.myLastCreatedElems.Clear();