1 // Copyright (C) 2007-2008 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
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File : SMESH_MeshEditor.cxx
24 // Created : Mon Apr 12 16:10:22 2004
25 // Author : Edward AGAPOV (eap)
27 #include "SMESH_MeshEditor.hxx"
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_QuadraticFaceOfNodes.hxx"
36 #include "SMDS_MeshGroup.hxx"
38 #include "SMESHDS_Group.hxx"
39 #include "SMESHDS_Mesh.hxx"
41 #include "SMESH_subMesh.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_MesherHelper.hxx"
44 #include "SMESH_OctreeNode.hxx"
45 #include "SMESH_Group.hxx"
47 #include "utilities.h"
49 #include <BRep_Tool.hxx>
50 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <Extrema_GenExtPS.hxx>
53 #include <Extrema_POnSurf.hxx>
54 #include <Geom2d_Curve.hxx>
55 #include <GeomAdaptor_Surface.hxx>
56 #include <Geom_Curve.hxx>
57 #include <Geom_Surface.hxx>
58 #include <Precision.hxx>
59 #include <TColStd_ListOfInteger.hxx>
60 #include <TopAbs_State.hxx>
62 #include <TopExp_Explorer.hxx>
63 #include <TopTools_ListIteratorOfListOfShape.hxx>
64 #include <TopTools_ListOfShape.hxx>
65 #include <TopTools_SequenceOfShape.hxx>
67 #include <TopoDS_Face.hxx>
73 #include <gp_Trsf.hxx>
84 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
87 using namespace SMESH::Controls;
89 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
90 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
91 //typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> > TNodeOfNodeVecMap;
92 //typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr;
93 //typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> > TElemOfVecOfMapNodesMap;
95 //=======================================================================
97 * \brief SMDS_MeshNode -> gp_XYZ convertor
99 //=======================================================================
101 struct TNodeXYZ : public gp_XYZ
103 TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {}
104 double Distance( const SMDS_MeshNode* n )
106 return gp_Vec( *this, TNodeXYZ( n )).Magnitude();
108 double SquareDistance( const SMDS_MeshNode* n )
110 return gp_Vec( *this, TNodeXYZ( n )).SquareMagnitude();
114 //=======================================================================
115 //function : SMESH_MeshEditor
117 //=======================================================================
119 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
120 :myMesh( theMesh ) // theMesh may be NULL
124 //=======================================================================
128 //=======================================================================
131 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
132 const SMDSAbs_ElementType type,
136 SMDS_MeshElement* e = 0;
137 int nbnode = node.size();
138 SMESHDS_Mesh* mesh = GetMeshDS();
142 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
143 else e = mesh->AddEdge (node[0], node[1] );
144 else if ( nbnode == 3 )
145 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
146 else e = mesh->AddEdge (node[0], node[1], node[2] );
151 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
152 else e = mesh->AddFace (node[0], node[1], node[2] );
153 else if (nbnode == 4)
154 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
155 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
156 else if (nbnode == 6)
157 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
158 node[4], node[5], ID);
159 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
161 else if (nbnode == 8)
162 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
163 node[4], node[5], node[6], node[7], ID);
164 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
165 node[4], node[5], node[6], node[7] );
167 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
168 else e = mesh->AddPolygonalFace (node );
174 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
175 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
176 else if (nbnode == 5)
177 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
181 else if (nbnode == 6)
182 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183 node[4], node[5], ID);
184 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
186 else if (nbnode == 8)
187 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
188 node[4], node[5], node[6], node[7], ID);
189 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
190 node[4], node[5], node[6], node[7] );
191 else if (nbnode == 10)
192 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193 node[4], node[5], node[6], node[7],
194 node[8], node[9], ID);
195 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
196 node[4], node[5], node[6], node[7],
198 else if (nbnode == 13)
199 if ( ID ) e = mesh->AddVolumeWithID(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 e = mesh->AddVolume (node[0], node[1], node[2], node[3],
204 node[4], node[5], node[6], node[7],
205 node[8], node[9], node[10],node[11],
207 else if (nbnode == 15)
208 if ( ID ) e = mesh->AddVolumeWithID(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],ID);
212 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
213 node[4], node[5], node[6], node[7],
214 node[8], node[9], node[10],node[11],
215 node[12],node[13],node[14] );
216 else if (nbnode == 20)
217 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
218 node[4], node[5], node[6], node[7],
219 node[8], node[9], node[10],node[11],
220 node[12],node[13],node[14],node[15],
221 node[16],node[17],node[18],node[19],ID);
222 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
223 node[4], node[5], node[6], node[7],
224 node[8], node[9], node[10],node[11],
225 node[12],node[13],node[14],node[15],
226 node[16],node[17],node[18],node[19] );
232 //=======================================================================
236 //=======================================================================
238 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
239 const SMDSAbs_ElementType type,
243 vector<const SMDS_MeshNode*> nodes;
244 nodes.reserve( nodeIDs.size() );
245 vector<int>::const_iterator id = nodeIDs.begin();
246 while ( id != nodeIDs.end() ) {
247 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
248 nodes.push_back( node );
252 return AddElement( nodes, type, isPoly, ID );
255 //=======================================================================
257 //purpose : Remove a node or an element.
258 // Modify a compute state of sub-meshes which become empty
259 //=======================================================================
261 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
264 myLastCreatedElems.Clear();
265 myLastCreatedNodes.Clear();
267 SMESHDS_Mesh* aMesh = GetMeshDS();
268 set< SMESH_subMesh *> smmap;
270 list<int>::const_iterator it = theIDs.begin();
271 for ( ; it != theIDs.end(); it++ ) {
272 const SMDS_MeshElement * elem;
274 elem = aMesh->FindNode( *it );
276 elem = aMesh->FindElement( *it );
280 // Notify VERTEX sub-meshes about modification
282 const SMDS_MeshNode* node = cast2Node( elem );
283 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
284 if ( int aShapeID = node->GetPosition()->GetShapeId() )
285 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
288 // Find sub-meshes to notify about modification
289 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
290 // while ( nodeIt->more() ) {
291 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
292 // const SMDS_PositionPtr& aPosition = node->GetPosition();
293 // if ( aPosition.get() ) {
294 // if ( int aShapeID = aPosition->GetShapeId() ) {
295 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
296 // smmap.insert( sm );
303 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
305 aMesh->RemoveElement( elem );
308 // Notify sub-meshes about modification
309 if ( !smmap.empty() ) {
310 set< SMESH_subMesh *>::iterator smIt;
311 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
312 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
315 // // Check if the whole mesh becomes empty
316 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
317 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
322 //=======================================================================
323 //function : FindShape
324 //purpose : Return an index of the shape theElem is on
325 // or zero if a shape not found
326 //=======================================================================
328 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
330 myLastCreatedElems.Clear();
331 myLastCreatedNodes.Clear();
333 SMESHDS_Mesh * aMesh = GetMeshDS();
334 if ( aMesh->ShapeToMesh().IsNull() )
337 if ( theElem->GetType() == SMDSAbs_Node ) {
338 const SMDS_PositionPtr& aPosition =
339 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
340 if ( aPosition.get() )
341 return aPosition->GetShapeId();
346 TopoDS_Shape aShape; // the shape a node is on
347 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
348 while ( nodeIt->more() ) {
349 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
350 const SMDS_PositionPtr& aPosition = node->GetPosition();
351 if ( aPosition.get() ) {
352 int aShapeID = aPosition->GetShapeId();
353 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
355 if ( sm->Contains( theElem ))
357 if ( aShape.IsNull() )
358 aShape = aMesh->IndexToShape( aShapeID );
361 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
366 // None of nodes is on a proper shape,
367 // find the shape among ancestors of aShape on which a node is
368 if ( aShape.IsNull() ) {
369 //MESSAGE ("::FindShape() - NONE node is on shape")
372 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
373 for ( ; ancIt.More(); ancIt.Next() ) {
374 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
375 if ( sm && sm->Contains( theElem ))
376 return aMesh->ShapeToIndex( ancIt.Value() );
379 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
383 //=======================================================================
384 //function : IsMedium
386 //=======================================================================
388 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
389 const SMDSAbs_ElementType typeToCheck)
391 bool isMedium = false;
392 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
393 while (it->more() && !isMedium ) {
394 const SMDS_MeshElement* elem = it->next();
395 isMedium = elem->IsMediumNode(node);
400 //=======================================================================
401 //function : ShiftNodesQuadTria
403 // Shift nodes in the array corresponded to quadratic triangle
404 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
405 //=======================================================================
406 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
408 const SMDS_MeshNode* nd1 = aNodes[0];
409 aNodes[0] = aNodes[1];
410 aNodes[1] = aNodes[2];
412 const SMDS_MeshNode* nd2 = aNodes[3];
413 aNodes[3] = aNodes[4];
414 aNodes[4] = aNodes[5];
418 //=======================================================================
419 //function : GetNodesFromTwoTria
421 // Shift nodes in the array corresponded to quadratic triangle
422 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
423 //=======================================================================
424 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
425 const SMDS_MeshElement * theTria2,
426 const SMDS_MeshNode* N1[],
427 const SMDS_MeshNode* N2[])
429 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
432 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
435 if(it->more()) return false;
436 it = theTria2->nodesIterator();
439 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
442 if(it->more()) return false;
444 int sames[3] = {-1,-1,-1};
456 if(nbsames!=2) return false;
458 ShiftNodesQuadTria(N1);
460 ShiftNodesQuadTria(N1);
463 i = sames[0] + sames[1] + sames[2];
465 ShiftNodesQuadTria(N2);
467 // now we receive following N1 and N2 (using numeration as above image)
468 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
469 // i.e. first nodes from both arrays determ new diagonal
473 //=======================================================================
474 //function : InverseDiag
475 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
476 // but having other common link.
477 // Return False if args are improper
478 //=======================================================================
480 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
481 const SMDS_MeshElement * theTria2 )
483 myLastCreatedElems.Clear();
484 myLastCreatedNodes.Clear();
486 if (!theTria1 || !theTria2)
489 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
490 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
493 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
494 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
498 // put nodes in array and find out indices of the same ones
499 const SMDS_MeshNode* aNodes [6];
500 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
502 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
503 while ( it->more() ) {
504 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
506 if ( i > 2 ) // theTria2
507 // find same node of theTria1
508 for ( int j = 0; j < 3; j++ )
509 if ( aNodes[ i ] == aNodes[ j ]) {
518 return false; // theTria1 is not a triangle
519 it = theTria2->nodesIterator();
521 if ( i == 6 && it->more() )
522 return false; // theTria2 is not a triangle
525 // find indices of 1,2 and of A,B in theTria1
526 int iA = 0, iB = 0, i1 = 0, i2 = 0;
527 for ( i = 0; i < 6; i++ ) {
528 if ( sameInd [ i ] == 0 )
535 // nodes 1 and 2 should not be the same
536 if ( aNodes[ i1 ] == aNodes[ i2 ] )
540 aNodes[ iA ] = aNodes[ i2 ];
542 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
544 //MESSAGE( theTria1 << theTria2 );
546 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
547 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
549 //MESSAGE( theTria1 << theTria2 );
553 } // end if(F1 && F2)
555 // check case of quadratic faces
556 const SMDS_QuadraticFaceOfNodes* QF1 =
557 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
558 if(!QF1) return false;
559 const SMDS_QuadraticFaceOfNodes* QF2 =
560 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
561 if(!QF2) return false;
564 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
565 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
573 const SMDS_MeshNode* N1 [6];
574 const SMDS_MeshNode* N2 [6];
575 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
577 // now we receive following N1 and N2 (using numeration as above image)
578 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
579 // i.e. first nodes from both arrays determ new diagonal
581 const SMDS_MeshNode* N1new [6];
582 const SMDS_MeshNode* N2new [6];
595 // replaces nodes in faces
596 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
597 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
602 //=======================================================================
603 //function : findTriangles
604 //purpose : find triangles sharing theNode1-theNode2 link
605 //=======================================================================
607 static bool findTriangles(const SMDS_MeshNode * theNode1,
608 const SMDS_MeshNode * theNode2,
609 const SMDS_MeshElement*& theTria1,
610 const SMDS_MeshElement*& theTria2)
612 if ( !theNode1 || !theNode2 ) return false;
614 theTria1 = theTria2 = 0;
616 set< const SMDS_MeshElement* > emap;
617 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
619 const SMDS_MeshElement* elem = it->next();
620 if ( elem->NbNodes() == 3 )
623 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
625 const SMDS_MeshElement* elem = it->next();
626 if ( emap.find( elem ) != emap.end() )
628 // theTria1 must be element with minimum ID
629 if( theTria1->GetID() < elem->GetID() ) {
642 return ( theTria1 && theTria2 );
645 //=======================================================================
646 //function : InverseDiag
647 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
648 // with ones built on the same 4 nodes but having other common link.
649 // Return false if proper faces not found
650 //=======================================================================
652 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
653 const SMDS_MeshNode * theNode2)
655 myLastCreatedElems.Clear();
656 myLastCreatedNodes.Clear();
658 MESSAGE( "::InverseDiag()" );
660 const SMDS_MeshElement *tr1, *tr2;
661 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
664 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
665 //if (!F1) return false;
666 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
667 //if (!F2) return false;
670 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
671 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
675 // put nodes in array
676 // and find indices of 1,2 and of A in tr1 and of B in tr2
677 int i, iA1 = 0, i1 = 0;
678 const SMDS_MeshNode* aNodes1 [3];
679 SMDS_ElemIteratorPtr it;
680 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
681 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
682 if ( aNodes1[ i ] == theNode1 )
683 iA1 = i; // node A in tr1
684 else if ( aNodes1[ i ] != theNode2 )
688 const SMDS_MeshNode* aNodes2 [3];
689 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
690 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
691 if ( aNodes2[ i ] == theNode2 )
692 iB2 = i; // node B in tr2
693 else if ( aNodes2[ i ] != theNode1 )
697 // nodes 1 and 2 should not be the same
698 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
702 aNodes1[ iA1 ] = aNodes2[ i2 ];
704 aNodes2[ iB2 ] = aNodes1[ i1 ];
706 //MESSAGE( tr1 << tr2 );
708 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
709 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
711 //MESSAGE( tr1 << tr2 );
716 // check case of quadratic faces
717 const SMDS_QuadraticFaceOfNodes* QF1 =
718 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
719 if(!QF1) return false;
720 const SMDS_QuadraticFaceOfNodes* QF2 =
721 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
722 if(!QF2) return false;
723 return InverseDiag(tr1,tr2);
726 //=======================================================================
727 //function : getQuadrangleNodes
728 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
729 // fusion of triangles tr1 and tr2 having shared link on
730 // theNode1 and theNode2
731 //=======================================================================
733 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
734 const SMDS_MeshNode * theNode1,
735 const SMDS_MeshNode * theNode2,
736 const SMDS_MeshElement * tr1,
737 const SMDS_MeshElement * tr2 )
739 if( tr1->NbNodes() != tr2->NbNodes() )
741 // find the 4-th node to insert into tr1
742 const SMDS_MeshNode* n4 = 0;
743 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
745 while ( !n4 && i<3 ) {
746 const SMDS_MeshNode * n = cast2Node( it->next() );
748 bool isDiag = ( n == theNode1 || n == theNode2 );
752 // Make an array of nodes to be in a quadrangle
753 int iNode = 0, iFirstDiag = -1;
754 it = tr1->nodesIterator();
757 const SMDS_MeshNode * n = cast2Node( it->next() );
759 bool isDiag = ( n == theNode1 || n == theNode2 );
761 if ( iFirstDiag < 0 )
763 else if ( iNode - iFirstDiag == 1 )
764 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
766 else if ( n == n4 ) {
767 return false; // tr1 and tr2 should not have all the same nodes
769 theQuadNodes[ iNode++ ] = n;
771 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
772 theQuadNodes[ iNode ] = n4;
777 //=======================================================================
778 //function : DeleteDiag
779 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
780 // with a quadrangle built on the same 4 nodes.
781 // Return false if proper faces not found
782 //=======================================================================
784 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
785 const SMDS_MeshNode * theNode2)
787 myLastCreatedElems.Clear();
788 myLastCreatedNodes.Clear();
790 MESSAGE( "::DeleteDiag()" );
792 const SMDS_MeshElement *tr1, *tr2;
793 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
796 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
797 //if (!F1) return false;
798 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
799 //if (!F2) return false;
802 const SMDS_MeshNode* aNodes [ 4 ];
803 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
806 //MESSAGE( endl << tr1 << tr2 );
808 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
809 myLastCreatedElems.Append(tr1);
810 GetMeshDS()->RemoveElement( tr2 );
812 //MESSAGE( endl << tr1 );
817 // check case of quadratic faces
818 const SMDS_QuadraticFaceOfNodes* QF1 =
819 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
820 if(!QF1) return false;
821 const SMDS_QuadraticFaceOfNodes* QF2 =
822 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
823 if(!QF2) return false;
826 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
827 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
835 const SMDS_MeshNode* N1 [6];
836 const SMDS_MeshNode* N2 [6];
837 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
839 // now we receive following N1 and N2 (using numeration as above image)
840 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
841 // i.e. first nodes from both arrays determ new diagonal
843 const SMDS_MeshNode* aNodes[8];
853 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
854 myLastCreatedElems.Append(tr1);
855 GetMeshDS()->RemoveElement( tr2 );
857 // remove middle node (9)
858 GetMeshDS()->RemoveNode( N1[4] );
863 //=======================================================================
864 //function : Reorient
865 //purpose : Reverse theElement orientation
866 //=======================================================================
868 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
870 myLastCreatedElems.Clear();
871 myLastCreatedNodes.Clear();
875 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
876 if ( !it || !it->more() )
879 switch ( theElem->GetType() ) {
883 if(!theElem->IsQuadratic()) {
884 int i = theElem->NbNodes();
885 vector<const SMDS_MeshNode*> aNodes( i );
887 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
888 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
891 // quadratic elements
892 if(theElem->GetType()==SMDSAbs_Edge) {
893 vector<const SMDS_MeshNode*> aNodes(3);
894 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
895 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
896 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
897 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
900 int nbn = theElem->NbNodes();
901 vector<const SMDS_MeshNode*> aNodes(nbn);
902 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
904 for(; i<nbn/2; i++) {
905 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
907 for(i=0; i<nbn/2; i++) {
908 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
910 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
914 case SMDSAbs_Volume: {
915 if (theElem->IsPoly()) {
916 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
917 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
919 MESSAGE("Warning: bad volumic element");
923 int nbFaces = aPolyedre->NbFaces();
924 vector<const SMDS_MeshNode *> poly_nodes;
925 vector<int> quantities (nbFaces);
927 // reverse each face of the polyedre
928 for (int iface = 1; iface <= nbFaces; iface++) {
929 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
930 quantities[iface - 1] = nbFaceNodes;
932 for (inode = nbFaceNodes; inode >= 1; inode--) {
933 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
934 poly_nodes.push_back(curNode);
938 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
942 SMDS_VolumeTool vTool;
943 if ( !vTool.Set( theElem ))
946 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
955 //=======================================================================
956 //function : getBadRate
958 //=======================================================================
960 static double getBadRate (const SMDS_MeshElement* theElem,
961 SMESH::Controls::NumericalFunctorPtr& theCrit)
963 SMESH::Controls::TSequenceOfXYZ P;
964 if ( !theElem || !theCrit->GetPoints( theElem, P ))
966 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
967 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
970 //=======================================================================
971 //function : QuadToTri
972 //purpose : Cut quadrangles into triangles.
973 // theCrit is used to select a diagonal to cut
974 //=======================================================================
976 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
977 SMESH::Controls::NumericalFunctorPtr theCrit)
979 myLastCreatedElems.Clear();
980 myLastCreatedNodes.Clear();
982 MESSAGE( "::QuadToTri()" );
984 if ( !theCrit.get() )
987 SMESHDS_Mesh * aMesh = GetMeshDS();
989 Handle(Geom_Surface) surface;
990 SMESH_MesherHelper helper( *GetMesh() );
992 TIDSortedElemSet::iterator itElem;
993 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
994 const SMDS_MeshElement* elem = *itElem;
995 if ( !elem || elem->GetType() != SMDSAbs_Face )
997 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1000 // retrieve element nodes
1001 const SMDS_MeshNode* aNodes [8];
1002 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1004 while ( itN->more() )
1005 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1007 // compare two sets of possible triangles
1008 double aBadRate1, aBadRate2; // to what extent a set is bad
1009 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1010 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1011 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1013 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1014 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1015 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1017 int aShapeId = FindShape( elem );
1018 const SMDS_MeshElement* newElem = 0;
1020 if( !elem->IsQuadratic() ) {
1022 // split liner quadrangle
1024 if ( aBadRate1 <= aBadRate2 ) {
1025 // tr1 + tr2 is better
1026 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1027 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1030 // tr3 + tr4 is better
1031 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1032 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1037 // split quadratic quadrangle
1039 // get surface elem is on
1040 if ( aShapeId != helper.GetSubShapeID() ) {
1044 shape = aMesh->IndexToShape( aShapeId );
1045 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1046 TopoDS_Face face = TopoDS::Face( shape );
1047 surface = BRep_Tool::Surface( face );
1048 if ( !surface.IsNull() )
1049 helper.SetSubShape( shape );
1053 const SMDS_MeshNode* aNodes [8];
1054 const SMDS_MeshNode* inFaceNode = 0;
1055 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1057 while ( itN->more() ) {
1058 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1059 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1060 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1062 inFaceNode = aNodes[ i-1 ];
1065 // find middle point for (0,1,2,3)
1066 // and create a node in this point;
1068 if ( surface.IsNull() ) {
1070 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1074 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1077 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1079 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1081 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1082 myLastCreatedNodes.Append(newN);
1084 // create a new element
1085 const SMDS_MeshNode* N[6];
1086 if ( aBadRate1 <= aBadRate2 ) {
1093 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1094 aNodes[6], aNodes[7], newN );
1103 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1104 aNodes[7], aNodes[4], newN );
1106 aMesh->ChangeElementNodes( elem, N, 6 );
1110 // care of a new element
1112 myLastCreatedElems.Append(newElem);
1113 AddToSameGroups( newElem, elem, aMesh );
1115 // put a new triangle on the same shape
1117 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1122 //=======================================================================
1123 //function : BestSplit
1124 //purpose : Find better diagonal for cutting.
1125 //=======================================================================
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
1167 //=======================================================================
1168 //function : AddToSameGroups
1169 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1170 //=======================================================================
1172 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1173 const SMDS_MeshElement* elemInGroups,
1174 SMESHDS_Mesh * aMesh)
1176 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1177 if (!groups.empty()) {
1178 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1179 for ( ; grIt != groups.end(); grIt++ ) {
1180 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1181 if ( group && group->Contains( elemInGroups ))
1182 group->SMDSGroup().Add( elemToAdd );
1188 //=======================================================================
1189 //function : RemoveElemFromGroups
1190 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1191 //=======================================================================
1192 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1193 SMESHDS_Mesh * aMesh)
1195 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1196 if (!groups.empty())
1198 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1199 for (; GrIt != groups.end(); GrIt++)
1201 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1202 if (!grp || grp->IsEmpty()) continue;
1203 grp->SMDSGroup().Remove(removeelem);
1208 //=======================================================================
1209 //function : ReplaceElemInGroups
1210 //purpose : replace elemToRm by elemToAdd in the all groups
1211 //=======================================================================
1213 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1214 const SMDS_MeshElement* elemToAdd,
1215 SMESHDS_Mesh * aMesh)
1217 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1218 if (!groups.empty()) {
1219 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1220 for ( ; grIt != groups.end(); grIt++ ) {
1221 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1222 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1223 group->SMDSGroup().Add( elemToAdd );
1228 //=======================================================================
1229 //function : QuadToTri
1230 //purpose : Cut quadrangles into triangles.
1231 // theCrit is used to select a diagonal to cut
1232 //=======================================================================
1234 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1235 const bool the13Diag)
1237 myLastCreatedElems.Clear();
1238 myLastCreatedNodes.Clear();
1240 MESSAGE( "::QuadToTri()" );
1242 SMESHDS_Mesh * aMesh = GetMeshDS();
1244 Handle(Geom_Surface) surface;
1245 SMESH_MesherHelper helper( *GetMesh() );
1247 TIDSortedElemSet::iterator itElem;
1248 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1249 const SMDS_MeshElement* elem = *itElem;
1250 if ( !elem || elem->GetType() != SMDSAbs_Face )
1252 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1253 if(!isquad) continue;
1255 if(elem->NbNodes()==4) {
1256 // retrieve element nodes
1257 const SMDS_MeshNode* aNodes [4];
1258 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1260 while ( itN->more() )
1261 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1263 int aShapeId = FindShape( elem );
1264 const SMDS_MeshElement* newElem = 0;
1266 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1267 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1270 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1271 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1273 myLastCreatedElems.Append(newElem);
1274 // put a new triangle on the same shape and add to the same groups
1276 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1277 AddToSameGroups( newElem, elem, aMesh );
1280 // Quadratic quadrangle
1282 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1284 // get surface elem is on
1285 int aShapeId = FindShape( elem );
1286 if ( aShapeId != helper.GetSubShapeID() ) {
1290 shape = aMesh->IndexToShape( aShapeId );
1291 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1292 TopoDS_Face face = TopoDS::Face( shape );
1293 surface = BRep_Tool::Surface( face );
1294 if ( !surface.IsNull() )
1295 helper.SetSubShape( shape );
1299 const SMDS_MeshNode* aNodes [8];
1300 const SMDS_MeshNode* inFaceNode = 0;
1301 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1303 while ( itN->more() ) {
1304 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1305 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1306 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1308 inFaceNode = aNodes[ i-1 ];
1312 // find middle point for (0,1,2,3)
1313 // and create a node in this point;
1315 if ( surface.IsNull() ) {
1317 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1321 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1324 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1326 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1328 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1329 myLastCreatedNodes.Append(newN);
1331 // create a new element
1332 const SMDS_MeshElement* newElem = 0;
1333 const SMDS_MeshNode* N[6];
1341 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1342 aNodes[6], aNodes[7], newN );
1351 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1352 aNodes[7], aNodes[4], newN );
1354 myLastCreatedElems.Append(newElem);
1355 aMesh->ChangeElementNodes( elem, N, 6 );
1356 // put a new triangle on the same shape and add to the same groups
1358 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1359 AddToSameGroups( newElem, elem, aMesh );
1366 //=======================================================================
1367 //function : getAngle
1369 //=======================================================================
1371 double getAngle(const SMDS_MeshElement * tr1,
1372 const SMDS_MeshElement * tr2,
1373 const SMDS_MeshNode * n1,
1374 const SMDS_MeshNode * n2)
1376 double angle = 2*PI; // bad angle
1379 SMESH::Controls::TSequenceOfXYZ P1, P2;
1380 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1381 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1384 if(!tr1->IsQuadratic())
1385 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1387 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1388 if ( N1.SquareMagnitude() <= gp::Resolution() )
1390 if(!tr2->IsQuadratic())
1391 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1393 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1394 if ( N2.SquareMagnitude() <= gp::Resolution() )
1397 // find the first diagonal node n1 in the triangles:
1398 // take in account a diagonal link orientation
1399 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1400 for ( int t = 0; t < 2; t++ ) {
1401 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1402 int i = 0, iDiag = -1;
1403 while ( it->more()) {
1404 const SMDS_MeshElement *n = it->next();
1405 if ( n == n1 || n == n2 )
1409 if ( i - iDiag == 1 )
1410 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1418 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1421 angle = N1.Angle( N2 );
1426 // =================================================
1427 // class generating a unique ID for a pair of nodes
1428 // and able to return nodes by that ID
1429 // =================================================
1433 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1434 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1437 long GetLinkID (const SMDS_MeshNode * n1,
1438 const SMDS_MeshNode * n2) const
1440 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1443 bool GetNodes (const long theLinkID,
1444 const SMDS_MeshNode* & theNode1,
1445 const SMDS_MeshNode* & theNode2) const
1447 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1448 if ( !theNode1 ) return false;
1449 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1450 if ( !theNode2 ) return false;
1456 const SMESHDS_Mesh* myMesh;
1461 //=======================================================================
1462 //function : TriToQuad
1463 //purpose : Fuse neighbour triangles into quadrangles.
1464 // theCrit is used to select a neighbour to fuse with.
1465 // theMaxAngle is a max angle between element normals at which
1466 // fusion is still performed.
1467 //=======================================================================
1469 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1470 SMESH::Controls::NumericalFunctorPtr theCrit,
1471 const double theMaxAngle)
1473 myLastCreatedElems.Clear();
1474 myLastCreatedNodes.Clear();
1476 MESSAGE( "::TriToQuad()" );
1478 if ( !theCrit.get() )
1481 SMESHDS_Mesh * aMesh = GetMeshDS();
1483 // Prepare data for algo: build
1484 // 1. map of elements with their linkIDs
1485 // 2. map of linkIDs with their elements
1487 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1488 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1489 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1490 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1492 TIDSortedElemSet::iterator itElem;
1493 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1494 const SMDS_MeshElement* elem = *itElem;
1495 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1496 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1497 if(!IsTria) continue;
1499 // retrieve element nodes
1500 const SMDS_MeshNode* aNodes [4];
1501 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1504 aNodes[ i++ ] = cast2Node( itN->next() );
1505 aNodes[ 3 ] = aNodes[ 0 ];
1508 for ( i = 0; i < 3; i++ ) {
1509 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1510 // check if elements sharing a link can be fused
1511 itLE = mapLi_listEl.find( link );
1512 if ( itLE != mapLi_listEl.end() ) {
1513 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1515 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1516 //if ( FindShape( elem ) != FindShape( elem2 ))
1517 // continue; // do not fuse triangles laying on different shapes
1518 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1519 continue; // avoid making badly shaped quads
1520 (*itLE).second.push_back( elem );
1523 mapLi_listEl[ link ].push_back( elem );
1525 mapEl_setLi [ elem ].insert( link );
1528 // Clean the maps from the links shared by a sole element, ie
1529 // links to which only one element is bound in mapLi_listEl
1531 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1532 int nbElems = (*itLE).second.size();
1533 if ( nbElems < 2 ) {
1534 const SMDS_MeshElement* elem = (*itLE).second.front();
1535 SMESH_TLink link = (*itLE).first;
1536 mapEl_setLi[ elem ].erase( link );
1537 if ( mapEl_setLi[ elem ].empty() )
1538 mapEl_setLi.erase( elem );
1542 // Algo: fuse triangles into quadrangles
1544 while ( ! mapEl_setLi.empty() ) {
1545 // Look for the start element:
1546 // the element having the least nb of shared links
1547 const SMDS_MeshElement* startElem = 0;
1549 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1550 int nbLinks = (*itEL).second.size();
1551 if ( nbLinks < minNbLinks ) {
1552 startElem = (*itEL).first;
1553 minNbLinks = nbLinks;
1554 if ( minNbLinks == 1 )
1559 // search elements to fuse starting from startElem or links of elements
1560 // fused earlyer - startLinks
1561 list< SMESH_TLink > startLinks;
1562 while ( startElem || !startLinks.empty() ) {
1563 while ( !startElem && !startLinks.empty() ) {
1564 // Get an element to start, by a link
1565 SMESH_TLink linkId = startLinks.front();
1566 startLinks.pop_front();
1567 itLE = mapLi_listEl.find( linkId );
1568 if ( itLE != mapLi_listEl.end() ) {
1569 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1570 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1571 for ( ; itE != listElem.end() ; itE++ )
1572 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1574 mapLi_listEl.erase( itLE );
1579 // Get candidates to be fused
1580 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1581 const SMESH_TLink *link12, *link13;
1583 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1584 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1585 ASSERT( !setLi.empty() );
1586 set< SMESH_TLink >::iterator itLi;
1587 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1589 const SMESH_TLink & link = (*itLi);
1590 itLE = mapLi_listEl.find( link );
1591 if ( itLE == mapLi_listEl.end() )
1594 const SMDS_MeshElement* elem = (*itLE).second.front();
1596 elem = (*itLE).second.back();
1597 mapLi_listEl.erase( itLE );
1598 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1609 // add other links of elem to list of links to re-start from
1610 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1611 set< SMESH_TLink >::iterator it;
1612 for ( it = links.begin(); it != links.end(); it++ ) {
1613 const SMESH_TLink& link2 = (*it);
1614 if ( link2 != link )
1615 startLinks.push_back( link2 );
1619 // Get nodes of possible quadrangles
1620 const SMDS_MeshNode *n12 [4], *n13 [4];
1621 bool Ok12 = false, Ok13 = false;
1622 const SMDS_MeshNode *linkNode1, *linkNode2;
1624 linkNode1 = link12->first;
1625 linkNode2 = link12->second;
1626 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1630 linkNode1 = link13->first;
1631 linkNode2 = link13->second;
1632 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1636 // Choose a pair to fuse
1637 if ( Ok12 && Ok13 ) {
1638 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1639 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1640 double aBadRate12 = getBadRate( &quad12, theCrit );
1641 double aBadRate13 = getBadRate( &quad13, theCrit );
1642 if ( aBadRate13 < aBadRate12 )
1649 // and remove fused elems and removed links from the maps
1650 mapEl_setLi.erase( tr1 );
1652 mapEl_setLi.erase( tr2 );
1653 mapLi_listEl.erase( *link12 );
1654 if(tr1->NbNodes()==3) {
1655 if( tr1->GetID() < tr2->GetID() ) {
1656 aMesh->ChangeElementNodes( tr1, n12, 4 );
1657 myLastCreatedElems.Append(tr1);
1658 aMesh->RemoveElement( tr2 );
1661 aMesh->ChangeElementNodes( tr2, n12, 4 );
1662 myLastCreatedElems.Append(tr2);
1663 aMesh->RemoveElement( tr1);
1667 const SMDS_MeshNode* N1 [6];
1668 const SMDS_MeshNode* N2 [6];
1669 GetNodesFromTwoTria(tr1,tr2,N1,N2);
1670 // now we receive following N1 and N2 (using numeration as above image)
1671 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1672 // i.e. first nodes from both arrays determ new diagonal
1673 const SMDS_MeshNode* aNodes[8];
1682 if( tr1->GetID() < tr2->GetID() ) {
1683 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1684 myLastCreatedElems.Append(tr1);
1685 GetMeshDS()->RemoveElement( tr2 );
1688 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1689 myLastCreatedElems.Append(tr2);
1690 GetMeshDS()->RemoveElement( tr1 );
1692 // remove middle node (9)
1693 GetMeshDS()->RemoveNode( N1[4] );
1697 mapEl_setLi.erase( tr3 );
1698 mapLi_listEl.erase( *link13 );
1699 if(tr1->NbNodes()==3) {
1700 if( tr1->GetID() < tr2->GetID() ) {
1701 aMesh->ChangeElementNodes( tr1, n13, 4 );
1702 myLastCreatedElems.Append(tr1);
1703 aMesh->RemoveElement( tr3 );
1706 aMesh->ChangeElementNodes( tr3, n13, 4 );
1707 myLastCreatedElems.Append(tr3);
1708 aMesh->RemoveElement( tr1 );
1712 const SMDS_MeshNode* N1 [6];
1713 const SMDS_MeshNode* N2 [6];
1714 GetNodesFromTwoTria(tr1,tr3,N1,N2);
1715 // now we receive following N1 and N2 (using numeration as above image)
1716 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1717 // i.e. first nodes from both arrays determ new diagonal
1718 const SMDS_MeshNode* aNodes[8];
1727 if( tr1->GetID() < tr2->GetID() ) {
1728 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1729 myLastCreatedElems.Append(tr1);
1730 GetMeshDS()->RemoveElement( tr3 );
1733 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1734 myLastCreatedElems.Append(tr3);
1735 GetMeshDS()->RemoveElement( tr1 );
1737 // remove middle node (9)
1738 GetMeshDS()->RemoveNode( N1[4] );
1742 // Next element to fuse: the rejected one
1744 startElem = Ok12 ? tr3 : tr2;
1746 } // if ( startElem )
1747 } // while ( startElem || !startLinks.empty() )
1748 } // while ( ! mapEl_setLi.empty() )
1754 /*#define DUMPSO(txt) \
1755 // cout << txt << endl;
1756 //=============================================================================
1760 //=============================================================================
1761 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1765 int tmp = idNodes[ i1 ];
1766 idNodes[ i1 ] = idNodes[ i2 ];
1767 idNodes[ i2 ] = tmp;
1768 gp_Pnt Ptmp = P[ i1 ];
1771 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1774 //=======================================================================
1775 //function : SortQuadNodes
1776 //purpose : Set 4 nodes of a quadrangle face in a good order.
1777 // Swap 1<->2 or 2<->3 nodes and correspondingly return
1779 //=======================================================================
1781 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1786 for ( i = 0; i < 4; i++ ) {
1787 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1789 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1792 gp_Vec V1(P[0], P[1]);
1793 gp_Vec V2(P[0], P[2]);
1794 gp_Vec V3(P[0], P[3]);
1796 gp_Vec Cross1 = V1 ^ V2;
1797 gp_Vec Cross2 = V2 ^ V3;
1800 if (Cross1.Dot(Cross2) < 0)
1805 if (Cross1.Dot(Cross2) < 0)
1809 swap ( i, i + 1, idNodes, P );
1811 // for ( int ii = 0; ii < 4; ii++ ) {
1812 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1813 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1819 //=======================================================================
1820 //function : SortHexaNodes
1821 //purpose : Set 8 nodes of a hexahedron in a good order.
1822 // Return success status
1823 //=======================================================================
1825 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1830 DUMPSO( "INPUT: ========================================");
1831 for ( i = 0; i < 8; i++ ) {
1832 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1833 if ( !n ) return false;
1834 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1835 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1837 DUMPSO( "========================================");
1840 set<int> faceNodes; // ids of bottom face nodes, to be found
1841 set<int> checkedId1; // ids of tried 2-nd nodes
1842 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1843 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
1844 int iMin, iLoop1 = 0;
1846 // Loop to try the 2-nd nodes
1848 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1850 // Find not checked 2-nd node
1851 for ( i = 1; i < 8; i++ )
1852 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1853 int id1 = idNodes[i];
1854 swap ( 1, i, idNodes, P );
1855 checkedId1.insert ( id1 );
1859 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1860 // ie that all but meybe one (id3 which is on the same face) nodes
1861 // lay on the same side from the triangle plane.
1863 bool manyInPlane = false; // more than 4 nodes lay in plane
1865 while ( ++iLoop2 < 6 ) {
1867 // get 1-2-3 plane coeffs
1868 Standard_Real A, B, C, D;
1869 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1870 if ( N.SquareMagnitude() > gp::Resolution() )
1872 gp_Pln pln ( P[0], N );
1873 pln.Coefficients( A, B, C, D );
1875 // find the node (iMin) closest to pln
1876 Standard_Real dist[ 8 ], minDist = DBL_MAX;
1878 for ( i = 3; i < 8; i++ ) {
1879 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1880 if ( fabs( dist[i] ) < minDist ) {
1881 minDist = fabs( dist[i] );
1884 if ( fabs( dist[i] ) <= tol )
1885 idInPln.insert( idNodes[i] );
1888 // there should not be more than 4 nodes in bottom plane
1889 if ( idInPln.size() > 1 )
1891 DUMPSO( "### idInPln.size() = " << idInPln.size());
1892 // idInPlane does not contain the first 3 nodes
1893 if ( manyInPlane || idInPln.size() == 5)
1894 return false; // all nodes in one plane
1897 // set the 1-st node to be not in plane
1898 for ( i = 3; i < 8; i++ ) {
1899 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1900 DUMPSO( "### Reset 0-th node");
1901 swap( 0, i, idNodes, P );
1906 // reset to re-check second nodes
1907 leastDist = DBL_MAX;
1911 break; // from iLoop2;
1914 // check that the other 4 nodes are on the same side
1915 bool sameSide = true;
1916 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1917 for ( i = 3; sameSide && i < 8; i++ ) {
1919 sameSide = ( isNeg == dist[i] <= 0.);
1922 // keep best solution
1923 if ( sameSide && minDist < leastDist ) {
1924 leastDist = minDist;
1926 faceNodes.insert( idNodes[ 1 ] );
1927 faceNodes.insert( idNodes[ 2 ] );
1928 faceNodes.insert( idNodes[ iMin ] );
1929 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1930 << " leastDist = " << leastDist);
1931 if ( leastDist <= DBL_MIN )
1936 // set next 3-d node to check
1937 int iNext = 2 + iLoop2;
1939 DUMPSO( "Try 2-nd");
1940 swap ( 2, iNext, idNodes, P );
1942 } // while ( iLoop2 < 6 )
1945 if ( faceNodes.empty() ) return false;
1947 // Put the faceNodes in proper places
1948 for ( i = 4; i < 8; i++ ) {
1949 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1950 // find a place to put
1952 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1954 DUMPSO( "Set faceNodes");
1955 swap ( iTo, i, idNodes, P );
1960 // Set nodes of the found bottom face in good order
1961 DUMPSO( " Found bottom face: ");
1962 i = SortQuadNodes( theMesh, idNodes );
1964 gp_Pnt Ptmp = P[ i ];
1969 // for ( int ii = 0; ii < 4; ii++ ) {
1970 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1971 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1974 // Gravity center of the top and bottom faces
1975 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1976 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1978 // Get direction from the bottom to the top face
1979 gp_Vec upDir ( aGCb, aGCt );
1980 Standard_Real upDirSize = upDir.Magnitude();
1981 if ( upDirSize <= gp::Resolution() ) return false;
1984 // Assure that the bottom face normal points up
1985 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1986 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1987 if ( Nb.Dot( upDir ) < 0 ) {
1988 DUMPSO( "Reverse bottom face");
1989 swap( 1, 3, idNodes, P );
1992 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1993 Standard_Real minDist = DBL_MAX;
1994 for ( i = 4; i < 8; i++ ) {
1995 // projection of P[i] to the plane defined by P[0] and upDir
1996 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1997 Standard_Real sqDist = P[0].SquareDistance( Pp );
1998 if ( sqDist < minDist ) {
2003 DUMPSO( "Set 4-th");
2004 swap ( 4, iMin, idNodes, P );
2006 // Set nodes of the top face in good order
2007 DUMPSO( "Sort top face");
2008 i = SortQuadNodes( theMesh, &idNodes[4] );
2011 gp_Pnt Ptmp = P[ i ];
2016 // Assure that direction of the top face normal is from the bottom face
2017 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2018 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2019 if ( Nt.Dot( upDir ) < 0 ) {
2020 DUMPSO( "Reverse top face");
2021 swap( 5, 7, idNodes, P );
2024 // DUMPSO( "OUTPUT: ========================================");
2025 // for ( i = 0; i < 8; i++ ) {
2026 // float *p = ugrid->GetPoint(idNodes[i]);
2027 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2033 //================================================================================
2035 * \brief Return nodes linked to the given one
2036 * \param theNode - the node
2037 * \param linkedNodes - the found nodes
2038 * \param type - the type of elements to check
2040 * Medium nodes are ignored
2042 //================================================================================
2044 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2045 TIDSortedElemSet & linkedNodes,
2046 SMDSAbs_ElementType type )
2048 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2049 while ( elemIt->more() )
2051 const SMDS_MeshElement* elem = elemIt->next();
2052 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2053 if ( elem->GetType() == SMDSAbs_Volume )
2055 SMDS_VolumeTool vol( elem );
2056 while ( nodeIt->more() ) {
2057 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2058 if ( theNode != n && vol.IsLinked( theNode, n ))
2059 linkedNodes.insert( n );
2064 for ( int i = 0; nodeIt->more(); ++i ) {
2065 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2066 if ( n == theNode ) {
2067 int iBefore = i - 1;
2069 if ( elem->IsQuadratic() ) {
2070 int nb = elem->NbNodes() / 2;
2071 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2072 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2074 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2075 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2082 //=======================================================================
2083 //function : laplacianSmooth
2084 //purpose : pulls theNode toward the center of surrounding nodes directly
2085 // connected to that node along an element edge
2086 //=======================================================================
2088 void laplacianSmooth(const SMDS_MeshNode* theNode,
2089 const Handle(Geom_Surface)& theSurface,
2090 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2092 // find surrounding nodes
2094 TIDSortedElemSet nodeSet;
2095 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2097 // compute new coodrs
2099 double coord[] = { 0., 0., 0. };
2100 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2101 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2102 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2103 if ( theSurface.IsNull() ) { // smooth in 3D
2104 coord[0] += node->X();
2105 coord[1] += node->Y();
2106 coord[2] += node->Z();
2108 else { // smooth in 2D
2109 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2110 gp_XY* uv = theUVMap[ node ];
2111 coord[0] += uv->X();
2112 coord[1] += uv->Y();
2115 int nbNodes = nodeSet.size();
2118 coord[0] /= nbNodes;
2119 coord[1] /= nbNodes;
2121 if ( !theSurface.IsNull() ) {
2122 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2123 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2124 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2130 coord[2] /= nbNodes;
2134 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2137 //=======================================================================
2138 //function : centroidalSmooth
2139 //purpose : pulls theNode toward the element-area-weighted centroid of the
2140 // surrounding elements
2141 //=======================================================================
2143 void centroidalSmooth(const SMDS_MeshNode* theNode,
2144 const Handle(Geom_Surface)& theSurface,
2145 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2147 gp_XYZ aNewXYZ(0.,0.,0.);
2148 SMESH::Controls::Area anAreaFunc;
2149 double totalArea = 0.;
2154 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2155 while ( elemIt->more() )
2157 const SMDS_MeshElement* elem = elemIt->next();
2160 gp_XYZ elemCenter(0.,0.,0.);
2161 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2162 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2163 int nn = elem->NbNodes();
2164 if(elem->IsQuadratic()) nn = nn/2;
2166 //while ( itN->more() ) {
2168 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2170 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2171 aNodePoints.push_back( aP );
2172 if ( !theSurface.IsNull() ) { // smooth in 2D
2173 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2174 gp_XY* uv = theUVMap[ aNode ];
2175 aP.SetCoord( uv->X(), uv->Y(), 0. );
2179 double elemArea = anAreaFunc.GetValue( aNodePoints );
2180 totalArea += elemArea;
2182 aNewXYZ += elemCenter * elemArea;
2184 aNewXYZ /= totalArea;
2185 if ( !theSurface.IsNull() ) {
2186 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2187 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2192 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2195 //=======================================================================
2196 //function : getClosestUV
2197 //purpose : return UV of closest projection
2198 //=======================================================================
2200 static bool getClosestUV (Extrema_GenExtPS& projector,
2201 const gp_Pnt& point,
2204 projector.Perform( point );
2205 if ( projector.IsDone() ) {
2206 double u, v, minVal = DBL_MAX;
2207 for ( int i = projector.NbExt(); i > 0; i-- )
2208 if ( projector.Value( i ) < minVal ) {
2209 minVal = projector.Value( i );
2210 projector.Point( i ).Parameter( u, v );
2212 result.SetCoord( u, v );
2218 //=======================================================================
2220 //purpose : Smooth theElements during theNbIterations or until a worst
2221 // element has aspect ratio <= theTgtAspectRatio.
2222 // Aspect Ratio varies in range [1.0, inf].
2223 // If theElements is empty, the whole mesh is smoothed.
2224 // theFixedNodes contains additionally fixed nodes. Nodes built
2225 // on edges and boundary nodes are always fixed.
2226 //=======================================================================
2228 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2229 set<const SMDS_MeshNode*> & theFixedNodes,
2230 const SmoothMethod theSmoothMethod,
2231 const int theNbIterations,
2232 double theTgtAspectRatio,
2235 myLastCreatedElems.Clear();
2236 myLastCreatedNodes.Clear();
2238 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2240 if ( theTgtAspectRatio < 1.0 )
2241 theTgtAspectRatio = 1.0;
2243 const double disttol = 1.e-16;
2245 SMESH::Controls::AspectRatio aQualityFunc;
2247 SMESHDS_Mesh* aMesh = GetMeshDS();
2249 if ( theElems.empty() ) {
2250 // add all faces to theElems
2251 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2252 while ( fIt->more() ) {
2253 const SMDS_MeshElement* face = fIt->next();
2254 theElems.insert( face );
2257 // get all face ids theElems are on
2258 set< int > faceIdSet;
2259 TIDSortedElemSet::iterator itElem;
2261 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2262 int fId = FindShape( *itElem );
2263 // check that corresponding submesh exists and a shape is face
2265 faceIdSet.find( fId ) == faceIdSet.end() &&
2266 aMesh->MeshElements( fId )) {
2267 TopoDS_Shape F = aMesh->IndexToShape( fId );
2268 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2269 faceIdSet.insert( fId );
2272 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2274 // ===============================================
2275 // smooth elements on each TopoDS_Face separately
2276 // ===============================================
2278 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2279 for ( ; fId != faceIdSet.rend(); ++fId ) {
2280 // get face surface and submesh
2281 Handle(Geom_Surface) surface;
2282 SMESHDS_SubMesh* faceSubMesh = 0;
2284 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2285 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2286 bool isUPeriodic = false, isVPeriodic = false;
2288 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2289 surface = BRep_Tool::Surface( face );
2290 faceSubMesh = aMesh->MeshElements( *fId );
2291 fToler2 = BRep_Tool::Tolerance( face );
2292 fToler2 *= fToler2 * 10.;
2293 isUPeriodic = surface->IsUPeriodic();
2295 vPeriod = surface->UPeriod();
2296 isVPeriodic = surface->IsVPeriodic();
2298 uPeriod = surface->VPeriod();
2299 surface->Bounds( u1, u2, v1, v2 );
2301 // ---------------------------------------------------------
2302 // for elements on a face, find movable and fixed nodes and
2303 // compute UV for them
2304 // ---------------------------------------------------------
2305 bool checkBoundaryNodes = false;
2306 bool isQuadratic = false;
2307 set<const SMDS_MeshNode*> setMovableNodes;
2308 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2309 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2310 list< const SMDS_MeshElement* > elemsOnFace;
2312 Extrema_GenExtPS projector;
2313 GeomAdaptor_Surface surfAdaptor;
2314 if ( !surface.IsNull() ) {
2315 surfAdaptor.Load( surface );
2316 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2318 int nbElemOnFace = 0;
2319 itElem = theElems.begin();
2320 // loop on not yet smoothed elements: look for elems on a face
2321 while ( itElem != theElems.end() ) {
2322 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2323 break; // all elements found
2325 const SMDS_MeshElement* elem = *itElem;
2326 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2327 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2331 elemsOnFace.push_back( elem );
2332 theElems.erase( itElem++ );
2336 isQuadratic = elem->IsQuadratic();
2338 // get movable nodes of elem
2339 const SMDS_MeshNode* node;
2340 SMDS_TypeOfPosition posType;
2341 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2342 int nn = 0, nbn = elem->NbNodes();
2343 if(elem->IsQuadratic())
2345 while ( nn++ < nbn ) {
2346 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2347 const SMDS_PositionPtr& pos = node->GetPosition();
2348 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2349 if (posType != SMDS_TOP_EDGE &&
2350 posType != SMDS_TOP_VERTEX &&
2351 theFixedNodes.find( node ) == theFixedNodes.end())
2353 // check if all faces around the node are on faceSubMesh
2354 // because a node on edge may be bound to face
2355 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2357 if ( faceSubMesh ) {
2358 while ( eIt->more() && all ) {
2359 const SMDS_MeshElement* e = eIt->next();
2360 all = faceSubMesh->Contains( e );
2364 setMovableNodes.insert( node );
2366 checkBoundaryNodes = true;
2368 if ( posType == SMDS_TOP_3DSPACE )
2369 checkBoundaryNodes = true;
2372 if ( surface.IsNull() )
2375 // get nodes to check UV
2376 list< const SMDS_MeshNode* > uvCheckNodes;
2377 itN = elem->nodesIterator();
2378 nn = 0; nbn = elem->NbNodes();
2379 if(elem->IsQuadratic())
2381 while ( nn++ < nbn ) {
2382 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2383 if ( uvMap.find( node ) == uvMap.end() )
2384 uvCheckNodes.push_back( node );
2385 // add nodes of elems sharing node
2386 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2387 // while ( eIt->more() ) {
2388 // const SMDS_MeshElement* e = eIt->next();
2389 // if ( e != elem ) {
2390 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2391 // while ( nIt->more() ) {
2392 // const SMDS_MeshNode* n =
2393 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2394 // if ( uvMap.find( n ) == uvMap.end() )
2395 // uvCheckNodes.push_back( n );
2401 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2402 for ( ; n != uvCheckNodes.end(); ++n ) {
2405 const SMDS_PositionPtr& pos = node->GetPosition();
2406 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2408 switch ( posType ) {
2409 case SMDS_TOP_FACE: {
2410 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2411 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2414 case SMDS_TOP_EDGE: {
2415 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2416 Handle(Geom2d_Curve) pcurve;
2417 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2418 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2419 if ( !pcurve.IsNull() ) {
2420 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2421 uv = pcurve->Value( u ).XY();
2425 case SMDS_TOP_VERTEX: {
2426 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2427 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2428 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2433 // check existing UV
2434 bool project = true;
2435 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2436 double dist1 = DBL_MAX, dist2 = 0;
2437 if ( posType != SMDS_TOP_3DSPACE ) {
2438 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2439 project = dist1 > fToler2;
2441 if ( project ) { // compute new UV
2443 if ( !getClosestUV( projector, pNode, newUV )) {
2444 MESSAGE("Node Projection Failed " << node);
2448 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2450 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2452 if ( posType != SMDS_TOP_3DSPACE )
2453 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2454 if ( dist2 < dist1 )
2458 // store UV in the map
2459 listUV.push_back( uv );
2460 uvMap.insert( make_pair( node, &listUV.back() ));
2462 } // loop on not yet smoothed elements
2464 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2465 checkBoundaryNodes = true;
2467 // fix nodes on mesh boundary
2469 if ( checkBoundaryNodes ) {
2470 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2471 map< NLink, int >::iterator link_nb;
2472 // put all elements links to linkNbMap
2473 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2474 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2475 const SMDS_MeshElement* elem = (*elemIt);
2476 int nbn = elem->NbNodes();
2477 if(elem->IsQuadratic())
2479 // loop on elem links: insert them in linkNbMap
2480 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2481 for ( int iN = 0; iN < nbn; ++iN ) {
2482 curNode = elem->GetNode( iN );
2484 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2485 else link = make_pair( prevNode , curNode );
2487 link_nb = linkNbMap.find( link );
2488 if ( link_nb == linkNbMap.end() )
2489 linkNbMap.insert( make_pair ( link, 1 ));
2494 // remove nodes that are in links encountered only once from setMovableNodes
2495 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2496 if ( link_nb->second == 1 ) {
2497 setMovableNodes.erase( link_nb->first.first );
2498 setMovableNodes.erase( link_nb->first.second );
2503 // -----------------------------------------------------
2504 // for nodes on seam edge, compute one more UV ( uvMap2 );
2505 // find movable nodes linked to nodes on seam and which
2506 // are to be smoothed using the second UV ( uvMap2 )
2507 // -----------------------------------------------------
2509 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2510 if ( !surface.IsNull() ) {
2511 TopExp_Explorer eExp( face, TopAbs_EDGE );
2512 for ( ; eExp.More(); eExp.Next() ) {
2513 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2514 if ( !BRep_Tool::IsClosed( edge, face ))
2516 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2517 if ( !sm ) continue;
2518 // find out which parameter varies for a node on seam
2521 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2522 if ( pcurve.IsNull() ) continue;
2523 uv1 = pcurve->Value( f );
2525 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2526 if ( pcurve.IsNull() ) continue;
2527 uv2 = pcurve->Value( f );
2528 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2530 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2531 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2533 // get nodes on seam and its vertices
2534 list< const SMDS_MeshNode* > seamNodes;
2535 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2536 while ( nSeamIt->more() ) {
2537 const SMDS_MeshNode* node = nSeamIt->next();
2538 if ( !isQuadratic || !IsMedium( node ))
2539 seamNodes.push_back( node );
2541 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2542 for ( ; vExp.More(); vExp.Next() ) {
2543 sm = aMesh->MeshElements( vExp.Current() );
2545 nSeamIt = sm->GetNodes();
2546 while ( nSeamIt->more() )
2547 seamNodes.push_back( nSeamIt->next() );
2550 // loop on nodes on seam
2551 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2552 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2553 const SMDS_MeshNode* nSeam = *noSeIt;
2554 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2555 if ( n_uv == uvMap.end() )
2558 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2559 // set the second UV
2560 listUV.push_back( *n_uv->second );
2561 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2562 if ( uvMap2.empty() )
2563 uvMap2 = uvMap; // copy the uvMap contents
2564 uvMap2[ nSeam ] = &listUV.back();
2566 // collect movable nodes linked to ones on seam in nodesNearSeam
2567 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2568 while ( eIt->more() ) {
2569 const SMDS_MeshElement* e = eIt->next();
2570 int nbUseMap1 = 0, nbUseMap2 = 0;
2571 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2572 int nn = 0, nbn = e->NbNodes();
2573 if(e->IsQuadratic()) nbn = nbn/2;
2574 while ( nn++ < nbn )
2576 const SMDS_MeshNode* n =
2577 static_cast<const SMDS_MeshNode*>( nIt->next() );
2579 setMovableNodes.find( n ) == setMovableNodes.end() )
2581 // add only nodes being closer to uv2 than to uv1
2582 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2583 0.5 * ( n->Y() + nSeam->Y() ),
2584 0.5 * ( n->Z() + nSeam->Z() ));
2586 getClosestUV( projector, pMid, uv );
2587 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2588 nodesNearSeam.insert( n );
2594 // for centroidalSmooth all element nodes must
2595 // be on one side of a seam
2596 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2597 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2599 while ( nn++ < nbn ) {
2600 const SMDS_MeshNode* n =
2601 static_cast<const SMDS_MeshNode*>( nIt->next() );
2602 setMovableNodes.erase( n );
2606 } // loop on nodes on seam
2607 } // loop on edge of a face
2608 } // if ( !face.IsNull() )
2610 if ( setMovableNodes.empty() ) {
2611 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2612 continue; // goto next face
2620 double maxRatio = -1., maxDisplacement = -1.;
2621 set<const SMDS_MeshNode*>::iterator nodeToMove;
2622 for ( it = 0; it < theNbIterations; it++ ) {
2623 maxDisplacement = 0.;
2624 nodeToMove = setMovableNodes.begin();
2625 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2626 const SMDS_MeshNode* node = (*nodeToMove);
2627 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2630 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2631 if ( theSmoothMethod == LAPLACIAN )
2632 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2634 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2636 // node displacement
2637 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2638 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2639 if ( aDispl > maxDisplacement )
2640 maxDisplacement = aDispl;
2642 // no node movement => exit
2643 //if ( maxDisplacement < 1.e-16 ) {
2644 if ( maxDisplacement < disttol ) {
2645 MESSAGE("-- no node movement --");
2649 // check elements quality
2651 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2652 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2653 const SMDS_MeshElement* elem = (*elemIt);
2654 if ( !elem || elem->GetType() != SMDSAbs_Face )
2656 SMESH::Controls::TSequenceOfXYZ aPoints;
2657 if ( aQualityFunc.GetPoints( elem, aPoints )) {
2658 double aValue = aQualityFunc.GetValue( aPoints );
2659 if ( aValue > maxRatio )
2663 if ( maxRatio <= theTgtAspectRatio ) {
2664 MESSAGE("-- quality achived --");
2667 if (it+1 == theNbIterations) {
2668 MESSAGE("-- Iteration limit exceeded --");
2670 } // smoothing iterations
2672 MESSAGE(" Face id: " << *fId <<
2673 " Nb iterstions: " << it <<
2674 " Displacement: " << maxDisplacement <<
2675 " Aspect Ratio " << maxRatio);
2677 // ---------------------------------------
2678 // new nodes positions are computed,
2679 // record movement in DS and set new UV
2680 // ---------------------------------------
2681 nodeToMove = setMovableNodes.begin();
2682 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2683 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2684 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2685 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2686 if ( node_uv != uvMap.end() ) {
2687 gp_XY* uv = node_uv->second;
2689 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2693 // move medium nodes of quadratic elements
2696 SMESH_MesherHelper helper( *GetMesh() );
2697 if ( !face.IsNull() )
2698 helper.SetSubShape( face );
2699 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2700 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2701 const SMDS_QuadraticFaceOfNodes* QF =
2702 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2704 vector<const SMDS_MeshNode*> Ns;
2705 Ns.reserve(QF->NbNodes()+1);
2706 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2707 while ( anIter->more() )
2708 Ns.push_back( anIter->next() );
2709 Ns.push_back( Ns[0] );
2711 for(int i=0; i<QF->NbNodes(); i=i+2) {
2712 if ( !surface.IsNull() ) {
2713 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2714 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2715 gp_XY uv = ( uv1 + uv2 ) / 2.;
2716 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2717 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2720 x = (Ns[i]->X() + Ns[i+2]->X())/2;
2721 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2722 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2724 if( fabs( Ns[i+1]->X() - x ) > disttol ||
2725 fabs( Ns[i+1]->Y() - y ) > disttol ||
2726 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2727 // we have to move i+1 node
2728 aMesh->MoveNode( Ns[i+1], x, y, z );
2735 } // loop on face ids
2739 //=======================================================================
2740 //function : isReverse
2741 //purpose : Return true if normal of prevNodes is not co-directied with
2742 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2743 // iNotSame is where prevNodes and nextNodes are different
2744 //=======================================================================
2746 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2747 vector<const SMDS_MeshNode*> nextNodes,
2751 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2752 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2754 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2755 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2756 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2757 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2759 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2760 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2761 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2762 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2764 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2766 return (vA ^ vB) * vN < 0.0;
2769 //=======================================================================
2771 * \brief Create elements by sweeping an element
2772 * \param elem - element to sweep
2773 * \param newNodesItVec - nodes generated from each node of the element
2774 * \param newElems - generated elements
2775 * \param nbSteps - number of sweeping steps
2776 * \param srcElements - to append elem for each generated element
2778 //=======================================================================
2780 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
2781 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2782 list<const SMDS_MeshElement*>& newElems,
2784 SMESH_SequenceOfElemPtr& srcElements)
2786 SMESHDS_Mesh* aMesh = GetMeshDS();
2788 // Loop on elem nodes:
2789 // find new nodes and detect same nodes indices
2790 int nbNodes = elem->NbNodes();
2791 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2792 vector<const SMDS_MeshNode*> prevNod( nbNodes );
2793 vector<const SMDS_MeshNode*> nextNod( nbNodes );
2794 vector<const SMDS_MeshNode*> midlNod( nbNodes );
2796 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2797 vector<int> sames(nbNodes);
2798 vector<bool> issimple(nbNodes);
2800 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2801 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2802 const SMDS_MeshNode* node = nnIt->first;
2803 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2804 if ( listNewNodes.empty() ) {
2808 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
2810 itNN[ iNode ] = listNewNodes.begin();
2811 prevNod[ iNode ] = node;
2812 nextNod[ iNode ] = listNewNodes.front();
2813 if( !elem->IsQuadratic() || !issimple[iNode] ) {
2814 if ( prevNod[ iNode ] != nextNod [ iNode ])
2815 iNotSameNode = iNode;
2819 sames[nbSame++] = iNode;
2824 //cout<<" nbSame = "<<nbSame<<endl;
2825 if ( nbSame == nbNodes || nbSame > 2) {
2826 MESSAGE( " Too many same nodes of element " << elem->GetID() );
2827 //INFOS( " Too many same nodes of element " << elem->GetID() );
2831 // if( elem->IsQuadratic() && nbSame>0 ) {
2832 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2836 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2837 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2839 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2840 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2841 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2845 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2846 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2847 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2848 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2850 // check element orientation
2852 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2853 //MESSAGE("Reversed elem " << elem );
2857 std::swap( iBeforeSame, iAfterSame );
2860 // make new elements
2861 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
2863 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2864 if(issimple[iNode]) {
2865 nextNod[ iNode ] = *itNN[ iNode ];
2869 if( elem->GetType()==SMDSAbs_Node ) {
2870 // we have to use two nodes
2871 midlNod[ iNode ] = *itNN[ iNode ];
2873 nextNod[ iNode ] = *itNN[ iNode ];
2876 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
2877 // we have to use each second node
2879 nextNod[ iNode ] = *itNN[ iNode ];
2883 // we have to use two nodes
2884 midlNod[ iNode ] = *itNN[ iNode ];
2886 nextNod[ iNode ] = *itNN[ iNode ];
2891 SMDS_MeshElement* aNewElem = 0;
2892 if(!elem->IsPoly()) {
2893 switch ( nbNodes ) {
2897 if ( nbSame == 0 ) {
2899 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2901 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2907 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2908 nextNod[ 1 ], nextNod[ 0 ] );
2910 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2911 nextNod[ iNotSameNode ] );
2915 case 3: { // TRIANGLE or quadratic edge
2916 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2918 if ( nbSame == 0 ) // --- pentahedron
2919 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2920 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2922 else if ( nbSame == 1 ) // --- pyramid
2923 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2924 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2925 nextNod[ iSameNode ]);
2927 else // 2 same nodes: --- tetrahedron
2928 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2929 nextNod[ iNotSameNode ]);
2931 else { // quadratic edge
2932 if(nbSame==0) { // quadratic quadrangle
2933 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2934 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2936 else if(nbSame==1) { // quadratic triangle
2938 return; // medium node on axis
2940 else if(sames[0]==0) {
2941 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2942 nextNod[2], midlNod[1], prevNod[2]);
2944 else { // sames[0]==1
2945 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2946 midlNod[0], nextNod[2], prevNod[2]);
2955 case 4: { // QUADRANGLE
2957 if ( nbSame == 0 ) // --- hexahedron
2958 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2959 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2961 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2962 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2963 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2964 nextNod[ iSameNode ]);
2965 newElems.push_back( aNewElem );
2966 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2967 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
2968 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
2970 else if ( nbSame == 2 ) { // pentahedron
2971 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2972 // iBeforeSame is same too
2973 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2974 nextNod[ iOpposSame ], prevNod[ iSameNode ],
2975 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
2977 // iAfterSame is same too
2978 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2979 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2980 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
2984 case 6: { // quadratic triangle
2985 // create pentahedron with 15 nodes
2987 if(i0>0) { // reversed case
2988 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2989 nextNod[0], nextNod[2], nextNod[1],
2990 prevNod[5], prevNod[4], prevNod[3],
2991 nextNod[5], nextNod[4], nextNod[3],
2992 midlNod[0], midlNod[2], midlNod[1]);
2994 else { // not reversed case
2995 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2996 nextNod[0], nextNod[1], nextNod[2],
2997 prevNod[3], prevNod[4], prevNod[5],
2998 nextNod[3], nextNod[4], nextNod[5],
2999 midlNod[0], midlNod[1], midlNod[2]);
3002 else if(nbSame==1) {
3003 // 2d order pyramid of 13 nodes
3004 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3005 // int n12,int n23,int n34,int n41,
3006 // int n15,int n25,int n35,int n45, int ID);
3008 int n1,n4,n41,n15,n45;
3009 if(i0>0) { // reversed case
3010 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3011 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3017 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3018 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3023 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3024 nextNod[n4], prevNod[n4], prevNod[n5],
3025 midlNod[n1], nextNod[n41],
3026 midlNod[n4], prevNod[n41],
3027 prevNod[n15], nextNod[n15],
3028 nextNod[n45], prevNod[n45]);
3030 else if(nbSame==2) {
3031 // 2d order tetrahedron of 10 nodes
3032 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3033 // int n12,int n23,int n31,
3034 // int n14,int n24,int n34, int ID);
3035 int n1 = iNotSameNode;
3036 int n2,n3,n12,n23,n31;
3037 if(i0>0) { // reversed case
3038 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3039 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3045 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3046 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3051 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3052 prevNod[n12], prevNod[n23], prevNod[n31],
3053 midlNod[n1], nextNod[n12], nextNod[n31]);
3057 case 8: { // quadratic quadrangle
3059 // create hexahedron with 20 nodes
3060 if(i0>0) { // reversed case
3061 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3062 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3063 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3064 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3065 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3067 else { // not reversed case
3068 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3069 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3070 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3071 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3072 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3075 else if(nbSame==1) {
3076 // --- pyramid + pentahedron - can not be created since it is needed
3077 // additional middle node ot the center of face
3078 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3081 else if(nbSame==2) {
3082 // 2d order Pentahedron with 15 nodes
3083 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3084 // int n12,int n23,int n31,int n45,int n56,int n64,
3085 // int n14,int n25,int n36, int ID);
3087 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3088 // iBeforeSame is same too
3095 // iAfterSame is same too
3101 int n12,n45,n14,n25;
3102 if(i0>0) { //reversed case
3114 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3115 prevNod[n4], prevNod[n5], nextNod[n5],
3116 prevNod[n12], midlNod[n2], nextNod[n12],
3117 prevNod[n45], midlNod[n5], nextNod[n45],
3118 prevNod[n14], prevNod[n25], nextNod[n25]);
3123 // realized for extrusion only
3124 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3125 //vector<int> quantities (nbNodes + 2);
3127 //quantities[0] = nbNodes; // bottom of prism
3128 //for (int inode = 0; inode < nbNodes; inode++) {
3129 // polyedre_nodes[inode] = prevNod[inode];
3132 //quantities[1] = nbNodes; // top of prism
3133 //for (int inode = 0; inode < nbNodes; inode++) {
3134 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3137 //for (int iface = 0; iface < nbNodes; iface++) {
3138 // quantities[iface + 2] = 4;
3139 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3140 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3141 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3142 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3143 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3145 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3152 // realized for extrusion only
3153 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3154 vector<int> quantities (nbNodes + 2);
3156 quantities[0] = nbNodes; // bottom of prism
3157 for (int inode = 0; inode < nbNodes; inode++) {
3158 polyedre_nodes[inode] = prevNod[inode];
3161 quantities[1] = nbNodes; // top of prism
3162 for (int inode = 0; inode < nbNodes; inode++) {
3163 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3166 for (int iface = 0; iface < nbNodes; iface++) {
3167 quantities[iface + 2] = 4;
3168 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3169 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3170 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3171 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3172 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3174 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3178 newElems.push_back( aNewElem );
3179 myLastCreatedElems.Append(aNewElem);
3180 srcElements.Append( elem );
3183 // set new prev nodes
3184 for ( iNode = 0; iNode < nbNodes; iNode++ )
3185 prevNod[ iNode ] = nextNod[ iNode ];
3190 //=======================================================================
3192 * \brief Create 1D and 2D elements around swept elements
3193 * \param mapNewNodes - source nodes and ones generated from them
3194 * \param newElemsMap - source elements and ones generated from them
3195 * \param elemNewNodesMap - nodes generated from each node of each element
3196 * \param elemSet - all swept elements
3197 * \param nbSteps - number of sweeping steps
3198 * \param srcElements - to append elem for each generated element
3200 //=======================================================================
3202 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3203 TElemOfElemListMap & newElemsMap,
3204 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3205 TIDSortedElemSet& elemSet,
3207 SMESH_SequenceOfElemPtr& srcElements)
3209 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3210 SMESHDS_Mesh* aMesh = GetMeshDS();
3212 // Find nodes belonging to only one initial element - sweep them to get edges.
3214 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3215 for ( ; nList != mapNewNodes.end(); nList++ ) {
3216 const SMDS_MeshNode* node =
3217 static_cast<const SMDS_MeshNode*>( nList->first );
3218 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3219 int nbInitElems = 0;
3220 const SMDS_MeshElement* el = 0;
3221 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3222 while ( eIt->more() && nbInitElems < 2 ) {
3224 SMDSAbs_ElementType type = el->GetType();
3225 if ( type == SMDSAbs_Volume || type < highType ) continue;
3226 if ( type > highType ) {
3230 if ( elemSet.find(el) != elemSet.end() )
3233 if ( nbInitElems < 2 ) {
3234 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3235 if(!NotCreateEdge) {
3236 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3237 list<const SMDS_MeshElement*> newEdges;
3238 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3243 // Make a ceiling for each element ie an equal element of last new nodes.
3244 // Find free links of faces - make edges and sweep them into faces.
3246 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3247 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3248 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3249 const SMDS_MeshElement* elem = itElem->first;
3250 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3252 if ( elem->GetType() == SMDSAbs_Edge ) {
3253 // create a ceiling edge
3254 if (!elem->IsQuadratic()) {
3255 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3256 vecNewNodes[ 1 ]->second.back())) {
3257 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3258 vecNewNodes[ 1 ]->second.back()));
3259 srcElements.Append( myLastCreatedElems.Last() );
3263 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3264 vecNewNodes[ 1 ]->second.back(),
3265 vecNewNodes[ 2 ]->second.back())) {
3266 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3267 vecNewNodes[ 1 ]->second.back(),
3268 vecNewNodes[ 2 ]->second.back()));
3269 srcElements.Append( myLastCreatedElems.Last() );
3273 if ( elem->GetType() != SMDSAbs_Face )
3276 if(itElem->second.size()==0) continue;
3278 bool hasFreeLinks = false;
3280 TIDSortedElemSet avoidSet;
3281 avoidSet.insert( elem );
3283 set<const SMDS_MeshNode*> aFaceLastNodes;
3284 int iNode, nbNodes = vecNewNodes.size();
3285 if(!elem->IsQuadratic()) {
3286 // loop on the face nodes
3287 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3288 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3289 // look for free links of the face
3290 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3291 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3292 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3293 // check if a link is free
3294 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3295 hasFreeLinks = true;
3296 // make an edge and a ceiling for a new edge
3297 if ( !aMesh->FindEdge( n1, n2 )) {
3298 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3299 srcElements.Append( myLastCreatedElems.Last() );
3301 n1 = vecNewNodes[ iNode ]->second.back();
3302 n2 = vecNewNodes[ iNext ]->second.back();
3303 if ( !aMesh->FindEdge( n1, n2 )) {
3304 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3305 srcElements.Append( myLastCreatedElems.Last() );
3310 else { // elem is quadratic face
3311 int nbn = nbNodes/2;
3312 for ( iNode = 0; iNode < nbn; iNode++ ) {
3313 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3314 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3315 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3316 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3317 // check if a link is free
3318 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3319 hasFreeLinks = true;
3320 // make an edge and a ceiling for a new edge
3322 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3323 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3324 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3325 srcElements.Append( myLastCreatedElems.Last() );
3327 n1 = vecNewNodes[ iNode ]->second.back();
3328 n2 = vecNewNodes[ iNext ]->second.back();
3329 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3330 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3331 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3332 srcElements.Append( myLastCreatedElems.Last() );
3336 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3337 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3341 // sweep free links into faces
3343 if ( hasFreeLinks ) {
3344 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3345 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3347 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3348 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3349 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3350 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3352 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3353 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3355 while ( iVol++ < volNb ) v++;
3356 // find indices of free faces of a volume and their source edges
3357 list< int > freeInd;
3358 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3359 SMDS_VolumeTool vTool( *v );
3360 int iF, nbF = vTool.NbFaces();
3361 for ( iF = 0; iF < nbF; iF ++ ) {
3362 if (vTool.IsFreeFace( iF ) &&
3363 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3364 initNodeSet != faceNodeSet) // except an initial face
3366 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3368 freeInd.push_back( iF );
3369 // find source edge of a free face iF
3370 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3371 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3372 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3373 initNodeSet.begin(), initNodeSet.end(),
3374 commonNodes.begin());
3375 if ( (*v)->IsQuadratic() )
3376 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3378 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3380 if ( !srcEdges.back() )
3382 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3383 << iF << " of volume #" << vTool.ID() << endl;
3388 if ( freeInd.empty() )
3391 // create faces for all steps;
3392 // if such a face has been already created by sweep of edge,
3393 // assure that its orientation is OK
3394 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3396 vTool.SetExternalNormal();
3397 list< int >::iterator ind = freeInd.begin();
3398 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3399 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3401 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3402 int nbn = vTool.NbFaceNodes( *ind );
3404 case 3: { ///// triangle
3405 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3407 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3408 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3409 aMesh->ChangeElementNodes( f, nodes, nbn );
3412 case 4: { ///// quadrangle
3413 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3415 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3416 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3417 aMesh->ChangeElementNodes( f, nodes, nbn );
3421 if( (*v)->IsQuadratic() ) {
3422 if(nbn==6) { /////// quadratic triangle
3423 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3424 nodes[1], nodes[3], nodes[5] );
3426 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3427 nodes[1], nodes[3], nodes[5]));
3429 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3430 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3431 tmpnodes[0] = nodes[0];
3432 tmpnodes[1] = nodes[2];
3433 tmpnodes[2] = nodes[4];
3434 tmpnodes[3] = nodes[1];
3435 tmpnodes[4] = nodes[3];
3436 tmpnodes[5] = nodes[5];
3437 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3440 else { /////// quadratic quadrangle
3441 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3442 nodes[1], nodes[3], nodes[5], nodes[7] );
3444 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3445 nodes[1], nodes[3], nodes[5], nodes[7]));
3447 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3448 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3449 tmpnodes[0] = nodes[0];
3450 tmpnodes[1] = nodes[2];
3451 tmpnodes[2] = nodes[4];
3452 tmpnodes[3] = nodes[6];
3453 tmpnodes[4] = nodes[1];
3454 tmpnodes[5] = nodes[3];
3455 tmpnodes[6] = nodes[5];
3456 tmpnodes[7] = nodes[7];
3457 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3461 else { //////// polygon
3462 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3463 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3465 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3466 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3467 aMesh->ChangeElementNodes( f, nodes, nbn );
3470 while ( srcElements.Length() < myLastCreatedElems.Length() )
3471 srcElements.Append( *srcEdge );
3473 } // loop on free faces
3475 // go to the next volume
3477 while ( iVol++ < nbVolumesByStep ) v++;
3480 } // sweep free links into faces
3482 // Make a ceiling face with a normal external to a volume
3484 SMDS_VolumeTool lastVol( itElem->second.back() );
3486 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3488 lastVol.SetExternalNormal();
3489 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3490 int nbn = lastVol.NbFaceNodes( iF );
3493 if (!hasFreeLinks ||
3494 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3495 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3498 if (!hasFreeLinks ||
3499 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3500 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3503 if(itElem->second.back()->IsQuadratic()) {
3505 if (!hasFreeLinks ||
3506 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3507 nodes[1], nodes[3], nodes[5]) ) {
3508 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3509 nodes[1], nodes[3], nodes[5]));
3513 if (!hasFreeLinks ||
3514 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3515 nodes[1], nodes[3], nodes[5], nodes[7]) )
3516 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3517 nodes[1], nodes[3], nodes[5], nodes[7]));
3521 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3522 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3523 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3527 while ( srcElements.Length() < myLastCreatedElems.Length() )
3528 srcElements.Append( myLastCreatedElems.Last() );
3530 } // loop on swept elements
3533 //=======================================================================
3534 //function : RotationSweep
3536 //=======================================================================
3538 SMESH_MeshEditor::PGroupIDs
3539 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3540 const gp_Ax1& theAxis,
3541 const double theAngle,
3542 const int theNbSteps,
3543 const double theTol,
3544 const bool theMakeGroups,
3545 const bool theMakeWalls)
3547 myLastCreatedElems.Clear();
3548 myLastCreatedNodes.Clear();
3550 // source elements for each generated one
3551 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3553 MESSAGE( "RotationSweep()");
3555 aTrsf.SetRotation( theAxis, theAngle );
3557 aTrsf2.SetRotation( theAxis, theAngle/2. );
3559 gp_Lin aLine( theAxis );
3560 double aSqTol = theTol * theTol;
3562 SMESHDS_Mesh* aMesh = GetMeshDS();
3564 TNodeOfNodeListMap mapNewNodes;
3565 TElemOfVecOfNnlmiMap mapElemNewNodes;
3566 TElemOfElemListMap newElemsMap;
3569 TIDSortedElemSet::iterator itElem;
3570 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3571 const SMDS_MeshElement* elem = *itElem;
3572 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3574 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3575 newNodesItVec.reserve( elem->NbNodes() );
3577 // loop on elem nodes
3578 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3579 while ( itN->more() ) {
3580 // check if a node has been already sweeped
3581 const SMDS_MeshNode* node = cast2Node( itN->next() );
3583 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3585 aXYZ.Coord( coord[0], coord[1], coord[2] );
3586 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3588 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3589 if ( nIt == mapNewNodes.end() ) {
3590 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3591 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3594 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3596 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3597 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3598 const SMDS_MeshNode * newNode = node;
3599 for ( int i = 0; i < theNbSteps; i++ ) {
3601 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3603 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3604 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3605 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3606 myLastCreatedNodes.Append(newNode);
3607 srcNodes.Append( node );
3608 listNewNodes.push_back( newNode );
3609 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3610 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3613 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3615 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3616 myLastCreatedNodes.Append(newNode);
3617 srcNodes.Append( node );
3618 listNewNodes.push_back( newNode );
3621 listNewNodes.push_back( newNode );
3622 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3623 listNewNodes.push_back( newNode );
3630 // if current elem is quadratic and current node is not medium
3631 // we have to check - may be it is needed to insert additional nodes
3632 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3633 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3634 if(listNewNodes.size()==theNbSteps) {
3635 listNewNodes.clear();
3637 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3639 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3640 const SMDS_MeshNode * newNode = node;
3642 for(int i = 0; i<theNbSteps; i++) {
3643 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3644 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3645 cout<<" 3 AddNode: "<<newNode;
3646 myLastCreatedNodes.Append(newNode);
3647 listNewNodes.push_back( newNode );
3648 srcNodes.Append( node );
3649 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3650 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3651 cout<<" 4 AddNode: "<<newNode;
3652 myLastCreatedNodes.Append(newNode);
3653 srcNodes.Append( node );
3654 listNewNodes.push_back( newNode );
3658 listNewNodes.push_back( newNode );
3664 newNodesItVec.push_back( nIt );
3666 // make new elements
3667 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3671 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3673 PGroupIDs newGroupIDs;
3674 if ( theMakeGroups )
3675 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3681 //=======================================================================
3682 //function : CreateNode
3684 //=======================================================================
3685 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3688 const double tolnode,
3689 SMESH_SequenceOfNode& aNodes)
3691 myLastCreatedElems.Clear();
3692 myLastCreatedNodes.Clear();
3695 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3697 // try to search in sequence of existing nodes
3698 // if aNodes.Length()>0 we 'nave to use given sequence
3699 // else - use all nodes of mesh
3700 if(aNodes.Length()>0) {
3702 for(i=1; i<=aNodes.Length(); i++) {
3703 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3704 if(P1.Distance(P2)<tolnode)
3705 return aNodes.Value(i);
3709 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3710 while(itn->more()) {
3711 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3712 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3713 if(P1.Distance(P2)<tolnode)
3718 // create new node and return it
3719 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3720 myLastCreatedNodes.Append(NewNode);
3725 //=======================================================================
3726 //function : ExtrusionSweep
3728 //=======================================================================
3730 SMESH_MeshEditor::PGroupIDs
3731 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3732 const gp_Vec& theStep,
3733 const int theNbSteps,
3734 TElemOfElemListMap& newElemsMap,
3735 const bool theMakeGroups,
3737 const double theTolerance)
3739 ExtrusParam aParams;
3740 aParams.myDir = gp_Dir(theStep);
3741 aParams.myNodes.Clear();
3742 aParams.mySteps = new TColStd_HSequenceOfReal;
3744 for(i=1; i<=theNbSteps; i++)
3745 aParams.mySteps->Append(theStep.Magnitude());
3748 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3752 //=======================================================================
3753 //function : ExtrusionSweep
3755 //=======================================================================
3757 SMESH_MeshEditor::PGroupIDs
3758 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3759 ExtrusParam& theParams,
3760 TElemOfElemListMap& newElemsMap,
3761 const bool theMakeGroups,
3763 const double theTolerance)
3765 myLastCreatedElems.Clear();
3766 myLastCreatedNodes.Clear();
3768 // source elements for each generated one
3769 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3771 SMESHDS_Mesh* aMesh = GetMeshDS();
3773 int nbsteps = theParams.mySteps->Length();
3775 TNodeOfNodeListMap mapNewNodes;
3776 //TNodeOfNodeVecMap mapNewNodes;
3777 TElemOfVecOfNnlmiMap mapElemNewNodes;
3778 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3781 TIDSortedElemSet::iterator itElem;
3782 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3783 // check element type
3784 const SMDS_MeshElement* elem = *itElem;
3785 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3788 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3789 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3790 newNodesItVec.reserve( elem->NbNodes() );
3792 // loop on elem nodes
3793 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3794 while ( itN->more() )
3796 // check if a node has been already sweeped
3797 const SMDS_MeshNode* node = cast2Node( itN->next() );
3798 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3799 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3800 if ( nIt == mapNewNodes.end() ) {
3801 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3802 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3803 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3804 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3805 //vecNewNodes.reserve(nbsteps);
3808 double coord[] = { node->X(), node->Y(), node->Z() };
3809 //int nbsteps = theParams.mySteps->Length();
3810 for ( int i = 0; i < nbsteps; i++ ) {
3811 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3812 // create additional node
3813 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3814 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3815 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3816 if( theFlags & EXTRUSION_FLAG_SEW ) {
3817 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3818 theTolerance, theParams.myNodes);
3819 listNewNodes.push_back( newNode );
3822 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3823 myLastCreatedNodes.Append(newNode);
3824 srcNodes.Append( node );
3825 listNewNodes.push_back( newNode );
3828 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3829 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3830 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3831 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3832 if( theFlags & EXTRUSION_FLAG_SEW ) {
3833 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3834 theTolerance, theParams.myNodes);
3835 listNewNodes.push_back( newNode );
3836 //vecNewNodes[i]=newNode;
3839 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3840 myLastCreatedNodes.Append(newNode);
3841 srcNodes.Append( node );
3842 listNewNodes.push_back( newNode );
3843 //vecNewNodes[i]=newNode;
3848 // if current elem is quadratic and current node is not medium
3849 // we have to check - may be it is needed to insert additional nodes
3850 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3851 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3852 if(listNewNodes.size()==nbsteps) {
3853 listNewNodes.clear();
3854 double coord[] = { node->X(), node->Y(), node->Z() };
3855 for ( int i = 0; i < nbsteps; i++ ) {
3856 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3857 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3858 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3859 if( theFlags & EXTRUSION_FLAG_SEW ) {
3860 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3861 theTolerance, theParams.myNodes);
3862 listNewNodes.push_back( newNode );
3865 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3866 myLastCreatedNodes.Append(newNode);
3867 srcNodes.Append( node );
3868 listNewNodes.push_back( newNode );
3870 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3871 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3872 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3873 if( theFlags & EXTRUSION_FLAG_SEW ) {
3874 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3875 theTolerance, theParams.myNodes);
3876 listNewNodes.push_back( newNode );
3879 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3880 myLastCreatedNodes.Append(newNode);
3881 srcNodes.Append( node );
3882 listNewNodes.push_back( newNode );
3888 newNodesItVec.push_back( nIt );
3890 // make new elements
3891 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
3894 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3895 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
3897 PGroupIDs newGroupIDs;
3898 if ( theMakeGroups )
3899 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
3905 //=======================================================================
3906 //class : SMESH_MeshEditor_PathPoint
3907 //purpose : auxiliary class
3908 //=======================================================================
3909 class SMESH_MeshEditor_PathPoint {
3911 SMESH_MeshEditor_PathPoint() {
3912 myPnt.SetCoord(99., 99., 99.);
3913 myTgt.SetCoord(1.,0.,0.);
3917 void SetPnt(const gp_Pnt& aP3D){
3920 void SetTangent(const gp_Dir& aTgt){
3923 void SetAngle(const double& aBeta){
3926 void SetParameter(const double& aPrm){
3929 const gp_Pnt& Pnt()const{
3932 const gp_Dir& Tangent()const{
3935 double Angle()const{
3938 double Parameter()const{
3950 //=======================================================================
3951 //function : ExtrusionAlongTrack
3953 //=======================================================================
3954 SMESH_MeshEditor::Extrusion_Error
3955 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3956 SMESH_subMesh* theTrack,
3957 const SMDS_MeshNode* theN1,
3958 const bool theHasAngles,
3959 list<double>& theAngles,
3960 const bool theLinearVariation,
3961 const bool theHasRefPoint,
3962 const gp_Pnt& theRefPoint,
3963 const bool theMakeGroups)
3965 myLastCreatedElems.Clear();
3966 myLastCreatedNodes.Clear();
3969 std::list<double> aPrms;
3970 TIDSortedElemSet::iterator itElem;
3973 TopoDS_Edge aTrackEdge;
3974 TopoDS_Vertex aV1, aV2;
3976 SMDS_ElemIteratorPtr aItE;
3977 SMDS_NodeIteratorPtr aItN;
3978 SMDSAbs_ElementType aTypeE;
3980 TNodeOfNodeListMap mapNewNodes;
3983 aNbE = theElements.size();
3986 return EXTR_NO_ELEMENTS;
3988 // 1.1 Track Pattern
3991 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
3993 aItE = pSubMeshDS->GetElements();
3994 while ( aItE->more() ) {
3995 const SMDS_MeshElement* pE = aItE->next();
3996 aTypeE = pE->GetType();
3997 // Pattern must contain links only
3998 if ( aTypeE != SMDSAbs_Edge )
3999 return EXTR_PATH_NOT_EDGE;
4002 list<SMESH_MeshEditor_PathPoint> fullList;
4004 const TopoDS_Shape& aS = theTrack->GetSubShape();
4005 // Sub shape for the Pattern must be an Edge or Wire
4006 if( aS.ShapeType() == TopAbs_EDGE ) {
4007 aTrackEdge = TopoDS::Edge( aS );
4008 // the Edge must not be degenerated
4009 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4010 return EXTR_BAD_PATH_SHAPE;
4011 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4012 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4013 const SMDS_MeshNode* aN1 = aItN->next();
4014 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4015 const SMDS_MeshNode* aN2 = aItN->next();
4016 // starting node must be aN1 or aN2
4017 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4018 return EXTR_BAD_STARTING_NODE;
4019 aItN = pSubMeshDS->GetNodes();
4020 while ( aItN->more() ) {
4021 const SMDS_MeshNode* pNode = aItN->next();
4022 const SMDS_EdgePosition* pEPos =
4023 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4024 double aT = pEPos->GetUParameter();
4025 aPrms.push_back( aT );
4027 //Extrusion_Error err =
4028 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4030 else if( aS.ShapeType() == TopAbs_WIRE ) {
4031 list< SMESH_subMesh* > LSM;
4032 TopTools_SequenceOfShape Edges;
4033 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4034 while(itSM->more()) {
4035 SMESH_subMesh* SM = itSM->next();
4037 const TopoDS_Shape& aS = SM->GetSubShape();
4040 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4041 int startNid = theN1->GetID();
4042 TColStd_MapOfInteger UsedNums;
4043 int NbEdges = Edges.Length();
4045 for(; i<=NbEdges; i++) {
4047 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4048 for(; itLSM!=LSM.end(); itLSM++) {
4050 if(UsedNums.Contains(k)) continue;
4051 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4052 SMESH_subMesh* locTrack = *itLSM;
4053 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4054 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4055 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4056 const SMDS_MeshNode* aN1 = aItN->next();
4057 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4058 const SMDS_MeshNode* aN2 = aItN->next();
4059 // starting node must be aN1 or aN2
4060 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4061 // 2. Collect parameters on the track edge
4063 aItN = locMeshDS->GetNodes();
4064 while ( aItN->more() ) {
4065 const SMDS_MeshNode* pNode = aItN->next();
4066 const SMDS_EdgePosition* pEPos =
4067 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4068 double aT = pEPos->GetUParameter();
4069 aPrms.push_back( aT );
4071 list<SMESH_MeshEditor_PathPoint> LPP;
4072 //Extrusion_Error err =
4073 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4074 LLPPs.push_back(LPP);
4076 // update startN for search following egde
4077 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4078 else startNid = aN1->GetID();
4082 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4083 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4084 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4085 for(; itPP!=firstList.end(); itPP++) {
4086 fullList.push_back( *itPP );
4088 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4089 fullList.pop_back();
4091 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4092 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4093 itPP = currList.begin();
4094 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4095 gp_Dir D1 = PP1.Tangent();
4096 gp_Dir D2 = PP2.Tangent();
4097 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4098 (D1.Z()+D2.Z())/2 ) );
4099 PP1.SetTangent(Dnew);
4100 fullList.push_back(PP1);
4102 for(; itPP!=firstList.end(); itPP++) {
4103 fullList.push_back( *itPP );
4105 PP1 = fullList.back();
4106 fullList.pop_back();
4108 // if wire not closed
4109 fullList.push_back(PP1);
4113 return EXTR_BAD_PATH_SHAPE;
4116 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4117 theHasRefPoint, theRefPoint, theMakeGroups);
4121 //=======================================================================
4122 //function : ExtrusionAlongTrack
4124 //=======================================================================
4125 SMESH_MeshEditor::Extrusion_Error
4126 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4127 SMESH_Mesh* theTrack,
4128 const SMDS_MeshNode* theN1,
4129 const bool theHasAngles,
4130 list<double>& theAngles,
4131 const bool theLinearVariation,
4132 const bool theHasRefPoint,
4133 const gp_Pnt& theRefPoint,
4134 const bool theMakeGroups)
4136 myLastCreatedElems.Clear();
4137 myLastCreatedNodes.Clear();
4140 std::list<double> aPrms;
4141 TIDSortedElemSet::iterator itElem;
4144 TopoDS_Edge aTrackEdge;
4145 TopoDS_Vertex aV1, aV2;
4147 SMDS_ElemIteratorPtr aItE;
4148 SMDS_NodeIteratorPtr aItN;
4149 SMDSAbs_ElementType aTypeE;
4151 TNodeOfNodeListMap mapNewNodes;
4154 aNbE = theElements.size();
4157 return EXTR_NO_ELEMENTS;
4159 // 1.1 Track Pattern
4162 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4164 aItE = pMeshDS->elementsIterator();
4165 while ( aItE->more() ) {
4166 const SMDS_MeshElement* pE = aItE->next();
4167 aTypeE = pE->GetType();
4168 // Pattern must contain links only
4169 if ( aTypeE != SMDSAbs_Edge )
4170 return EXTR_PATH_NOT_EDGE;
4173 list<SMESH_MeshEditor_PathPoint> fullList;
4175 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4176 // Sub shape for the Pattern must be an Edge or Wire
4177 if( aS.ShapeType() == TopAbs_EDGE ) {
4178 aTrackEdge = TopoDS::Edge( aS );
4179 // the Edge must not be degenerated
4180 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4181 return EXTR_BAD_PATH_SHAPE;
4182 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4183 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4184 const SMDS_MeshNode* aN1 = aItN->next();
4185 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4186 const SMDS_MeshNode* aN2 = aItN->next();
4187 // starting node must be aN1 or aN2
4188 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4189 return EXTR_BAD_STARTING_NODE;
4190 aItN = pMeshDS->nodesIterator();
4191 while ( aItN->more() ) {
4192 const SMDS_MeshNode* pNode = aItN->next();
4193 if( pNode==aN1 || pNode==aN2 ) continue;
4194 const SMDS_EdgePosition* pEPos =
4195 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4196 double aT = pEPos->GetUParameter();
4197 aPrms.push_back( aT );
4199 //Extrusion_Error err =
4200 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4202 else if( aS.ShapeType() == TopAbs_WIRE ) {
4203 list< SMESH_subMesh* > LSM;
4204 TopTools_SequenceOfShape Edges;
4205 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4206 for(; eExp.More(); eExp.Next()) {
4207 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4208 if( BRep_Tool::Degenerated(E) ) continue;
4209 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4215 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4216 int startNid = theN1->GetID();
4217 TColStd_MapOfInteger UsedNums;
4218 int NbEdges = Edges.Length();
4220 for(; i<=NbEdges; i++) {
4222 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4223 for(; itLSM!=LSM.end(); itLSM++) {
4225 if(UsedNums.Contains(k)) continue;
4226 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4227 SMESH_subMesh* locTrack = *itLSM;
4228 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4229 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4230 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4231 const SMDS_MeshNode* aN1 = aItN->next();
4232 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4233 const SMDS_MeshNode* aN2 = aItN->next();
4234 // starting node must be aN1 or aN2
4235 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4236 // 2. Collect parameters on the track edge
4238 aItN = locMeshDS->GetNodes();
4239 while ( aItN->more() ) {
4240 const SMDS_MeshNode* pNode = aItN->next();
4241 const SMDS_EdgePosition* pEPos =
4242 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4243 double aT = pEPos->GetUParameter();
4244 aPrms.push_back( aT );
4246 list<SMESH_MeshEditor_PathPoint> LPP;
4247 //Extrusion_Error err =
4248 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4249 LLPPs.push_back(LPP);
4251 // update startN for search following egde
4252 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4253 else startNid = aN1->GetID();
4257 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4258 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4259 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4260 for(; itPP!=firstList.end(); itPP++) {
4261 fullList.push_back( *itPP );
4263 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4264 fullList.pop_back();
4266 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4267 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4268 itPP = currList.begin();
4269 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4270 gp_Pnt P1 = PP1.Pnt();
4271 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4272 gp_Pnt P2 = PP2.Pnt();
4273 gp_Dir D1 = PP1.Tangent();
4274 gp_Dir D2 = PP2.Tangent();
4275 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4276 (D1.Z()+D2.Z())/2 ) );
4277 PP1.SetTangent(Dnew);
4278 fullList.push_back(PP1);
4280 for(; itPP!=currList.end(); itPP++) {
4281 fullList.push_back( *itPP );
4283 PP1 = fullList.back();
4284 fullList.pop_back();
4286 // if wire not closed
4287 fullList.push_back(PP1);
4291 return EXTR_BAD_PATH_SHAPE;
4294 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4295 theHasRefPoint, theRefPoint, theMakeGroups);
4299 //=======================================================================
4300 //function : MakeEdgePathPoints
4301 //purpose : auxilary for ExtrusionAlongTrack
4302 //=======================================================================
4303 SMESH_MeshEditor::Extrusion_Error
4304 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4305 const TopoDS_Edge& aTrackEdge,
4307 list<SMESH_MeshEditor_PathPoint>& LPP)
4309 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4311 aTolVec2=aTolVec*aTolVec;
4313 TopoDS_Vertex aV1, aV2;
4314 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4315 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4316 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4317 // 2. Collect parameters on the track edge
4318 aPrms.push_front( aT1 );
4319 aPrms.push_back( aT2 );
4322 if( FirstIsStart ) {
4333 SMESH_MeshEditor_PathPoint aPP;
4334 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4335 std::list<double>::iterator aItD = aPrms.begin();
4336 for(; aItD != aPrms.end(); ++aItD) {
4340 aC3D->D1( aT, aP3D, aVec );
4341 aL2 = aVec.SquareMagnitude();
4342 if ( aL2 < aTolVec2 )
4343 return EXTR_CANT_GET_TANGENT;
4344 gp_Dir aTgt( aVec );
4346 aPP.SetTangent( aTgt );
4347 aPP.SetParameter( aT );
4354 //=======================================================================
4355 //function : MakeExtrElements
4356 //purpose : auxilary for ExtrusionAlongTrack
4357 //=======================================================================
4358 SMESH_MeshEditor::Extrusion_Error
4359 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4360 list<SMESH_MeshEditor_PathPoint>& fullList,
4361 const bool theHasAngles,
4362 list<double>& theAngles,
4363 const bool theLinearVariation,
4364 const bool theHasRefPoint,
4365 const gp_Pnt& theRefPoint,
4366 const bool theMakeGroups)
4368 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4369 int aNbTP = fullList.size();
4370 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4372 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4373 LinearAngleVariation(aNbTP-1, theAngles);
4375 vector<double> aAngles( aNbTP );
4377 for(; j<aNbTP; ++j) {
4380 if ( theHasAngles ) {
4382 std::list<double>::iterator aItD = theAngles.begin();
4383 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4385 aAngles[j] = anAngle;
4388 // fill vector of path points with angles
4389 //aPPs.resize(fullList.size());
4391 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4392 for(; itPP!=fullList.end(); itPP++) {
4394 SMESH_MeshEditor_PathPoint PP = *itPP;
4395 PP.SetAngle(aAngles[j]);
4399 TNodeOfNodeListMap mapNewNodes;
4400 TElemOfVecOfNnlmiMap mapElemNewNodes;
4401 TElemOfElemListMap newElemsMap;
4402 TIDSortedElemSet::iterator itElem;
4405 SMDSAbs_ElementType aTypeE;
4406 // source elements for each generated one
4407 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4409 // 3. Center of rotation aV0
4410 gp_Pnt aV0 = theRefPoint;
4412 if ( !theHasRefPoint ) {
4414 aGC.SetCoord( 0.,0.,0. );
4416 itElem = theElements.begin();
4417 for ( ; itElem != theElements.end(); itElem++ ) {
4418 const SMDS_MeshElement* elem = *itElem;
4420 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4421 while ( itN->more() ) {
4422 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4427 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4428 list<const SMDS_MeshNode*> aLNx;
4429 mapNewNodes[node] = aLNx;
4431 gp_XYZ aXYZ( aX, aY, aZ );
4439 } // if (!theHasRefPoint) {
4440 mapNewNodes.clear();
4442 // 4. Processing the elements
4443 SMESHDS_Mesh* aMesh = GetMeshDS();
4445 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4446 // check element type
4447 const SMDS_MeshElement* elem = *itElem;
4448 aTypeE = elem->GetType();
4449 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4452 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4453 newNodesItVec.reserve( elem->NbNodes() );
4455 // loop on elem nodes
4457 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4458 while ( itN->more() )
4461 // check if a node has been already processed
4462 const SMDS_MeshNode* node =
4463 static_cast<const SMDS_MeshNode*>( itN->next() );
4464 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4465 if ( nIt == mapNewNodes.end() ) {
4466 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4467 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4470 aX = node->X(); aY = node->Y(); aZ = node->Z();
4472 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4473 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4474 gp_Ax1 anAx1, anAxT1T0;
4475 gp_Dir aDT1x, aDT0x, aDT1T0;
4480 aPN0.SetCoord(aX, aY, aZ);
4482 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4484 aDT0x= aPP0.Tangent();
4485 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4487 for ( j = 1; j < aNbTP; ++j ) {
4488 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4490 aDT1x = aPP1.Tangent();
4491 aAngle1x = aPP1.Angle();
4493 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4495 gp_Vec aV01x( aP0x, aP1x );
4496 aTrsf.SetTranslation( aV01x );
4499 aV1x = aV0x.Transformed( aTrsf );
4500 aPN1 = aPN0.Transformed( aTrsf );
4502 // rotation 1 [ T1,T0 ]
4503 aAngleT1T0=-aDT1x.Angle( aDT0x );
4504 if (fabs(aAngleT1T0) > aTolAng) {
4506 anAxT1T0.SetLocation( aV1x );
4507 anAxT1T0.SetDirection( aDT1T0 );
4508 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4510 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4514 if ( theHasAngles ) {
4515 anAx1.SetLocation( aV1x );
4516 anAx1.SetDirection( aDT1x );
4517 aTrsfRot.SetRotation( anAx1, aAngle1x );
4519 aPN1 = aPN1.Transformed( aTrsfRot );
4523 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4524 // create additional node
4525 double x = ( aPN1.X() + aPN0.X() )/2.;
4526 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4527 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4528 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4529 myLastCreatedNodes.Append(newNode);
4530 srcNodes.Append( node );
4531 listNewNodes.push_back( newNode );
4536 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4537 myLastCreatedNodes.Append(newNode);
4538 srcNodes.Append( node );
4539 listNewNodes.push_back( newNode );
4549 // if current elem is quadratic and current node is not medium
4550 // we have to check - may be it is needed to insert additional nodes
4551 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4552 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4553 if(listNewNodes.size()==aNbTP-1) {
4554 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4555 gp_XYZ P(node->X(), node->Y(), node->Z());
4556 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4558 for(i=0; i<aNbTP-1; i++) {
4559 const SMDS_MeshNode* N = *it;
4560 double x = ( N->X() + P.X() )/2.;
4561 double y = ( N->Y() + P.Y() )/2.;
4562 double z = ( N->Z() + P.Z() )/2.;
4563 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4564 srcNodes.Append( node );
4565 myLastCreatedNodes.Append(newN);
4568 P = gp_XYZ(N->X(),N->Y(),N->Z());
4570 listNewNodes.clear();
4571 for(i=0; i<2*(aNbTP-1); i++) {
4572 listNewNodes.push_back(aNodes[i]);
4578 newNodesItVec.push_back( nIt );
4580 // make new elements
4581 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4582 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4583 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4586 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4588 if ( theMakeGroups )
4589 generateGroups( srcNodes, srcElems, "extruded");
4595 //=======================================================================
4596 //function : LinearAngleVariation
4597 //purpose : auxilary for ExtrusionAlongTrack
4598 //=======================================================================
4599 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4600 list<double>& Angles)
4602 int nbAngles = Angles.size();
4603 if( nbSteps > nbAngles ) {
4604 vector<double> theAngles(nbAngles);
4605 list<double>::iterator it = Angles.begin();
4607 for(; it!=Angles.end(); it++) {
4609 theAngles[i] = (*it);
4612 double rAn2St = double( nbAngles ) / double( nbSteps );
4613 double angPrev = 0, angle;
4614 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4615 double angCur = rAn2St * ( iSt+1 );
4616 double angCurFloor = floor( angCur );
4617 double angPrevFloor = floor( angPrev );
4618 if ( angPrevFloor == angCurFloor )
4619 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4621 int iP = int( angPrevFloor );
4622 double angPrevCeil = ceil(angPrev);
4623 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4625 int iC = int( angCurFloor );
4626 if ( iC < nbAngles )
4627 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4629 iP = int( angPrevCeil );
4631 angle += theAngles[ iC ];
4633 res.push_back(angle);
4638 for(; it!=res.end(); it++)
4639 Angles.push_back( *it );
4644 //=======================================================================
4645 //function : Transform
4647 //=======================================================================
4649 SMESH_MeshEditor::PGroupIDs
4650 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4651 const gp_Trsf& theTrsf,
4653 const bool theMakeGroups,
4654 SMESH_Mesh* theTargetMesh)
4656 myLastCreatedElems.Clear();
4657 myLastCreatedNodes.Clear();
4659 bool needReverse = false;
4660 string groupPostfix;
4661 switch ( theTrsf.Form() ) {
4666 groupPostfix = "mirrored";
4669 groupPostfix = "rotated";
4671 case gp_Translation:
4672 groupPostfix = "translated";
4675 groupPostfix = "scaled";
4678 needReverse = false;
4679 groupPostfix = "transformed";
4682 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4683 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4684 SMESHDS_Mesh* aMesh = GetMeshDS();
4687 // map old node to new one
4688 TNodeNodeMap nodeMap;
4690 // elements sharing moved nodes; those of them which have all
4691 // nodes mirrored but are not in theElems are to be reversed
4692 TIDSortedElemSet inverseElemSet;
4694 // source elements for each generated one
4695 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4698 TIDSortedElemSet::iterator itElem;
4699 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4700 const SMDS_MeshElement* elem = *itElem;
4704 // loop on elem nodes
4705 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4706 while ( itN->more() ) {
4708 // check if a node has been already transformed
4709 const SMDS_MeshNode* node = cast2Node( itN->next() );
4710 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4711 nodeMap.insert( make_pair ( node, node ));
4712 if ( !n2n_isnew.second )
4716 coord[0] = node->X();
4717 coord[1] = node->Y();
4718 coord[2] = node->Z();
4719 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4720 if ( theTargetMesh ) {
4721 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4722 n2n_isnew.first->second = newNode;
4723 myLastCreatedNodes.Append(newNode);
4724 srcNodes.Append( node );
4726 else if ( theCopy ) {
4727 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4728 n2n_isnew.first->second = newNode;
4729 myLastCreatedNodes.Append(newNode);
4730 srcNodes.Append( node );
4733 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4734 // node position on shape becomes invalid
4735 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4736 ( SMDS_SpacePosition::originSpacePosition() );
4739 // keep inverse elements
4740 if ( !theCopy && !theTargetMesh && needReverse ) {
4741 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4742 while ( invElemIt->more() ) {
4743 const SMDS_MeshElement* iel = invElemIt->next();
4744 inverseElemSet.insert( iel );
4750 // either create new elements or reverse mirrored ones
4751 if ( !theCopy && !needReverse && !theTargetMesh )
4754 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4755 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4756 theElems.insert( *invElemIt );
4758 // replicate or reverse elements
4761 REV_TETRA = 0, // = nbNodes - 4
4762 REV_PYRAMID = 1, // = nbNodes - 4
4763 REV_PENTA = 2, // = nbNodes - 4
4765 REV_HEXA = 4, // = nbNodes - 4
4769 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4770 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4771 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4772 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4773 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4774 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4777 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4779 const SMDS_MeshElement* elem = *itElem;
4780 if ( !elem || elem->GetType() == SMDSAbs_Node )
4783 int nbNodes = elem->NbNodes();
4784 int elemType = elem->GetType();
4786 if (elem->IsPoly()) {
4787 // Polygon or Polyhedral Volume
4788 switch ( elemType ) {
4791 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4793 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4794 while (itN->more()) {
4795 const SMDS_MeshNode* node =
4796 static_cast<const SMDS_MeshNode*>(itN->next());
4797 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4798 if (nodeMapIt == nodeMap.end())
4799 break; // not all nodes transformed
4801 // reverse mirrored faces and volumes
4802 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4804 poly_nodes[iNode] = (*nodeMapIt).second;
4808 if ( iNode != nbNodes )
4809 continue; // not all nodes transformed
4811 if ( theTargetMesh ) {
4812 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4813 srcElems.Append( elem );
4815 else if ( theCopy ) {
4816 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4817 srcElems.Append( elem );
4820 aMesh->ChangePolygonNodes(elem, poly_nodes);
4824 case SMDSAbs_Volume:
4826 // ATTENTION: Reversing is not yet done!!!
4827 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4828 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4830 MESSAGE("Warning: bad volumic element");
4834 vector<const SMDS_MeshNode*> poly_nodes;
4835 vector<int> quantities;
4837 bool allTransformed = true;
4838 int nbFaces = aPolyedre->NbFaces();
4839 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4840 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4841 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4842 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4843 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4844 if (nodeMapIt == nodeMap.end()) {
4845 allTransformed = false; // not all nodes transformed
4847 poly_nodes.push_back((*nodeMapIt).second);
4850 quantities.push_back(nbFaceNodes);
4852 if ( !allTransformed )
4853 continue; // not all nodes transformed
4855 if ( theTargetMesh ) {
4856 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4857 srcElems.Append( elem );
4859 else if ( theCopy ) {
4860 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4861 srcElems.Append( elem );
4864 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4874 int* i = index[ FORWARD ];
4875 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4876 if ( elemType == SMDSAbs_Face )
4877 i = index[ REV_FACE ];
4879 i = index[ nbNodes - 4 ];
4881 if(elem->IsQuadratic()) {
4882 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4885 if(nbNodes==3) { // quadratic edge
4886 static int anIds[] = {1,0,2};
4889 else if(nbNodes==6) { // quadratic triangle
4890 static int anIds[] = {0,2,1,5,4,3};
4893 else if(nbNodes==8) { // quadratic quadrangle
4894 static int anIds[] = {0,3,2,1,7,6,5,4};
4897 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4898 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4901 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4902 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4905 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4906 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4909 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4910 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4916 // find transformed nodes
4917 vector<const SMDS_MeshNode*> nodes(nbNodes);
4919 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4920 while ( itN->more() ) {
4921 const SMDS_MeshNode* node =
4922 static_cast<const SMDS_MeshNode*>( itN->next() );
4923 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4924 if ( nodeMapIt == nodeMap.end() )
4925 break; // not all nodes transformed
4926 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4928 if ( iNode != nbNodes )
4929 continue; // not all nodes transformed
4931 if ( theTargetMesh ) {
4932 if ( SMDS_MeshElement* copy =
4933 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4934 myLastCreatedElems.Append( copy );
4935 srcElems.Append( elem );
4938 else if ( theCopy ) {
4939 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4940 myLastCreatedElems.Append( copy );
4941 srcElems.Append( elem );
4945 // reverse element as it was reversed by transformation
4947 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4951 PGroupIDs newGroupIDs;
4953 if ( theMakeGroups && theCopy ||
4954 theMakeGroups && theTargetMesh )
4955 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4960 //=======================================================================
4962 * \brief Create groups of elements made during transformation
4963 * \param nodeGens - nodes making corresponding myLastCreatedNodes
4964 * \param elemGens - elements making corresponding myLastCreatedElems
4965 * \param postfix - to append to names of new groups
4967 //=======================================================================
4969 SMESH_MeshEditor::PGroupIDs
4970 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4971 const SMESH_SequenceOfElemPtr& elemGens,
4972 const std::string& postfix,
4973 SMESH_Mesh* targetMesh)
4975 PGroupIDs newGroupIDs( new list<int> );
4976 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4978 // Sort existing groups by types and collect their names
4980 // to store an old group and a generated new one
4981 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4982 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4984 set< string > groupNames;
4986 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4987 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4988 while ( groupIt->more() ) {
4989 SMESH_Group * group = groupIt->next();
4990 if ( !group ) continue;
4991 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4992 if ( !groupDS || groupDS->IsEmpty() ) continue;
4993 groupNames.insert( group->GetName() );
4994 groupDS->SetStoreName( group->GetName() );
4995 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5000 // loop on nodes and elements
5001 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5003 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5004 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5005 if ( gens.Length() != elems.Length() )
5006 throw SALOME_Exception(LOCALIZED("invalid args"));
5008 // loop on created elements
5009 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5011 const SMDS_MeshElement* sourceElem = gens( iElem );
5012 if ( !sourceElem ) {
5013 MESSAGE("generateGroups(): NULL source element");
5016 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5017 if ( groupsOldNew.empty() ) {
5018 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5019 ++iElem; // skip all elements made by sourceElem
5022 // collect all elements made by sourceElem
5023 list< const SMDS_MeshElement* > resultElems;
5024 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5025 if ( resElem != sourceElem )
5026 resultElems.push_back( resElem );
5027 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5028 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5029 if ( resElem != sourceElem )
5030 resultElems.push_back( resElem );
5031 // do not generate element groups from node ones
5032 if ( sourceElem->GetType() == SMDSAbs_Node &&
5033 elems( iElem )->GetType() != SMDSAbs_Node )
5036 // add resultElems to groups made by ones the sourceElem belongs to
5037 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5038 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5040 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5041 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5043 SMDS_MeshGroup* & newGroup = gOldNew->second;
5044 if ( !newGroup )// create a new group
5047 string name = oldGroup->GetStoreName();
5048 if ( !targetMesh ) {
5052 while ( !groupNames.insert( name ).second ) // name exists
5058 TCollection_AsciiString nbStr(nb+1);
5059 name.resize( name.rfind('_')+1 );
5060 name += nbStr.ToCString();
5067 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5069 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5070 newGroup = & groupDS->SMDSGroup();
5071 newGroupIDs->push_back( id );
5074 // fill in a new group
5075 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5076 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5077 newGroup->Add( *resElemIt );
5080 } // loop on created elements
5081 }// loop on nodes and elements
5086 //================================================================================
5088 * \brief Return list of group of nodes close to each other within theTolerance
5089 * Search among theNodes or in the whole mesh if theNodes is empty using
5090 * an Octree algorithm
5092 //================================================================================
5094 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5095 const double theTolerance,
5096 TListOfListOfNodes & theGroupsOfNodes)
5098 myLastCreatedElems.Clear();
5099 myLastCreatedNodes.Clear();
5101 set<const SMDS_MeshNode*> nodes;
5102 if ( theNodes.empty() )
5103 { // get all nodes in the mesh
5104 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5105 while ( nIt->more() )
5106 nodes.insert( nodes.end(),nIt->next());
5111 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5115 //=======================================================================
5117 * \brief Implementation of search for the node closest to point
5119 //=======================================================================
5121 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5123 //---------------------------------------------------------------------
5125 * \brief Constructor
5127 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5129 myMesh = ( SMESHDS_Mesh* ) theMesh;
5131 set<const SMDS_MeshNode*> nodes;
5133 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5134 while ( nIt->more() )
5135 nodes.insert( nodes.end(), nIt->next() );
5137 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5139 // get max size of a leaf box
5140 SMESH_OctreeNode* tree = myOctreeNode;
5141 while ( !tree->isLeaf() )
5143 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5147 myHalfLeafSize = tree->maxSize() / 2.;
5150 //---------------------------------------------------------------------
5152 * \brief Move node and update myOctreeNode accordingly
5154 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5156 myOctreeNode->UpdateByMoveNode( node, toPnt );
5157 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5160 //---------------------------------------------------------------------
5162 * \brief Do it's job
5164 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5166 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5167 map<double, const SMDS_MeshNode*> dist2Nodes;
5168 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5169 if ( !dist2Nodes.empty() )
5170 return dist2Nodes.begin()->second;
5171 list<const SMDS_MeshNode*> nodes;
5172 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5174 double minSqDist = DBL_MAX;
5175 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5177 // sort leafs by their distance from thePnt
5178 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5179 TDistTreeMap treeMap;
5180 list< SMESH_OctreeNode* > treeList;
5181 list< SMESH_OctreeNode* >::iterator trIt;
5182 treeList.push_back( myOctreeNode );
5184 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5185 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5187 SMESH_OctreeNode* tree = *trIt;
5188 if ( !tree->isLeaf() ) // put children to the queue
5190 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5191 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5192 while ( cIt->more() )
5193 treeList.push_back( cIt->next() );
5195 else if ( tree->NbNodes() ) // put a tree to the treeMap
5197 const Bnd_B3d& box = tree->getBox();
5198 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5199 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5200 if ( !it_in.second ) // not unique distance to box center
5201 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5204 // find distance after which there is no sense to check tree's
5205 double sqLimit = DBL_MAX;
5206 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5207 if ( treeMap.size() > 5 ) {
5208 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5209 const Bnd_B3d& box = closestTree->getBox();
5210 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5211 sqLimit = limit * limit;
5213 // get all nodes from trees
5214 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5215 if ( sqDist_tree->first > sqLimit )
5217 SMESH_OctreeNode* tree = sqDist_tree->second;
5218 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5221 // find closest among nodes
5222 minSqDist = DBL_MAX;
5223 const SMDS_MeshNode* closestNode = 0;
5224 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5225 for ( ; nIt != nodes.end(); ++nIt ) {
5226 double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
5227 if ( minSqDist > sqDist ) {
5235 //---------------------------------------------------------------------
5239 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5241 //---------------------------------------------------------------------
5243 * \brief Return the node tree
5245 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5248 SMESH_OctreeNode* myOctreeNode;
5249 SMESHDS_Mesh* myMesh;
5250 double myHalfLeafSize; // max size of a leaf box
5253 //=======================================================================
5255 * \brief Return SMESH_NodeSearcher
5257 //=======================================================================
5259 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5261 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5264 // ========================================================================
5265 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5267 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5268 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5269 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5271 //=======================================================================
5273 * \brief Octal tree of bounding boxes of elements
5275 //=======================================================================
5277 class ElementBndBoxTree : public SMESH_Octree
5281 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5282 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5283 ~ElementBndBoxTree();
5286 ElementBndBoxTree() {}
5287 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5288 void buildChildrenData();
5289 Bnd_B3d* buildRootBox();
5291 //!< Bounding box of element
5292 struct ElementBox : public Bnd_B3d
5294 const SMDS_MeshElement* _element;
5295 int _refCount; // an ElementBox can be included in several tree branches
5296 ElementBox(const SMDS_MeshElement* elem);
5298 vector< ElementBox* > _elements;
5301 //================================================================================
5303 * \brief ElementBndBoxTree creation
5305 //================================================================================
5307 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5308 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5310 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5311 _elements.reserve( nbElems );
5313 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5314 while ( elemIt->more() )
5315 _elements.push_back( new ElementBox( elemIt->next() ));
5317 if ( _elements.size() > MaxNbElemsInLeaf )
5323 //================================================================================
5327 //================================================================================
5329 ElementBndBoxTree::~ElementBndBoxTree()
5331 for ( int i = 0; i < _elements.size(); ++i )
5332 if ( --_elements[i]->_refCount <= 0 )
5333 delete _elements[i];
5336 //================================================================================
5338 * \brief Return the maximal box
5340 //================================================================================
5342 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5344 Bnd_B3d* box = new Bnd_B3d;
5345 for ( int i = 0; i < _elements.size(); ++i )
5346 box->Add( *_elements[i] );
5350 //================================================================================
5352 * \brief Redistrubute element boxes among children
5354 //================================================================================
5356 void ElementBndBoxTree::buildChildrenData()
5358 for ( int i = 0; i < _elements.size(); ++i )
5360 for (int j = 0; j < 8; j++)
5362 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5364 _elements[i]->_refCount++;
5365 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5368 _elements[i]->_refCount--;
5372 for (int j = 0; j < 8; j++)
5374 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5375 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5376 child->myIsLeaf = true;
5378 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5379 child->_elements.resize( child->_elements.size() ); // compact
5383 //================================================================================
5385 * \brief Return elements which can include the point
5387 //================================================================================
5389 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5390 TIDSortedElemSet& foundElems)
5392 if ( level() && getBox().IsOut( point.XYZ() ))
5397 for ( int i = 0; i < _elements.size(); ++i )
5398 if ( !_elements[i]->IsOut( point.XYZ() ))
5399 foundElems.insert( _elements[i]->_element );
5403 for (int i = 0; i < 8; i++)
5404 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5408 //================================================================================
5410 * \brief Construct the element box
5412 //================================================================================
5414 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5418 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5419 while ( nIt->more() )
5420 Add( TNodeXYZ( cast2Node( nIt->next() )));
5421 Enlarge( NodeRadius );
5426 //=======================================================================
5428 * \brief Implementation of search for the elements by point
5430 //=======================================================================
5432 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5434 SMESHDS_Mesh* _mesh;
5435 ElementBndBoxTree* _ebbTree;
5436 SMESH_NodeSearcherImpl* _nodeSearcher;
5437 SMDSAbs_ElementType _elementType;
5439 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh ): _mesh(&mesh),_ebbTree(0),_nodeSearcher(0) {}
5440 ~SMESH_ElementSearcherImpl()
5442 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
5443 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5447 * \brief Return elements of given type where the given point is IN or ON.
5449 * 'ALL' type means elements of any type excluding nodes and 0D elements
5451 void FindElementsByPoint(const gp_Pnt& point,
5452 SMDSAbs_ElementType type,
5453 vector< const SMDS_MeshElement* >& foundElements)
5455 foundElements.clear();
5457 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5459 // -----------------
5461 // -----------------
5462 double tolerance = 0;
5463 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5465 double boxSize = _nodeSearcher->getTree()->maxSize();
5466 tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
5468 else if ( _ebbTree && meshInfo.NbElements() > 0 )
5470 double boxSize = _ebbTree->maxSize();
5471 tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
5473 if ( tolerance == 0 )
5475 // define tolerance by size of a most complex element
5476 int complexType = SMDSAbs_Volume;
5477 while ( complexType > SMDSAbs_All &&
5478 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
5480 if ( complexType == SMDSAbs_All ) return; // empty mesh
5483 if ( complexType == int( SMDSAbs_Node ))
5485 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
5487 if ( meshInfo.NbNodes() > 2 )
5488 elemSize = TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
5492 const SMDS_MeshElement* elem =
5493 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
5494 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
5495 TNodeXYZ n1( cast2Node( nodeIt->next() ));
5496 while ( nodeIt->more() )
5498 double dist = n1.Distance( cast2Node( nodeIt->next() ));
5499 elemSize = max( dist, elemSize );
5502 tolerance = 1e-6 * elemSize;
5505 // =================================================================================
5506 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
5508 if ( !_nodeSearcher )
5509 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
5511 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
5512 if ( !closeNode ) return;
5514 if ( point.Distance( TNodeXYZ( closeNode )) > tolerance )
5515 return; // to far from any node
5517 if ( type == SMDSAbs_Node )
5519 foundElements.push_back( closeNode );
5523 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
5524 while ( elemIt->more() )
5525 foundElements.push_back( elemIt->next() );
5528 // =================================================================================
5529 else // elements more complex than 0D
5531 if ( !_ebbTree || _elementType != type )
5533 if ( _ebbTree ) delete _ebbTree;
5534 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
5536 TIDSortedElemSet suspectElems;
5537 _ebbTree->getElementsNearPoint( point, suspectElems );
5538 TIDSortedElemSet::iterator elem = suspectElems.begin();
5539 for ( ; elem != suspectElems.end(); ++elem )
5540 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
5541 foundElements.push_back( *elem );
5544 }; // struct SMESH_ElementSearcherImpl
5546 //=======================================================================
5548 * \brief Return SMESH_ElementSearcher
5550 //=======================================================================
5552 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
5554 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
5557 //=======================================================================
5559 * \brief Return true if the point is IN or ON of the element
5561 //=======================================================================
5563 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
5565 if ( element->GetType() == SMDSAbs_Volume)
5567 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
5570 // get ordered nodes
5572 vector< gp_XYZ > xyz;
5574 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
5575 if ( element->IsQuadratic() )
5576 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
5577 nodeIt = f->interlacedNodesElemIterator();
5578 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
5579 nodeIt = e->interlacedNodesElemIterator();
5581 while ( nodeIt->more() )
5582 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
5584 int i, nbNodes = element->NbNodes();
5586 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
5588 // compute face normal
5589 gp_Vec faceNorm(0,0,0);
5590 xyz.push_back( xyz.front() );
5591 for ( i = 0; i < nbNodes; ++i )
5593 gp_Vec edge1( xyz[i+1], xyz[i]);
5594 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
5595 faceNorm += edge1 ^ edge2;
5597 double normSize = faceNorm.Magnitude();
5598 if ( normSize <= tol )
5600 // degenerated face: point is out if it is out of all face edges
5601 for ( i = 0; i < nbNodes; ++i )
5603 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
5604 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
5605 SMDS_MeshEdge edge( &n1, &n2 );
5606 if ( !isOut( &edge, point, tol ))
5611 faceNorm /= normSize;
5613 // check if the point lays on face plane
5614 gp_Vec n2p( xyz[0], point );
5615 if ( fabs( n2p * faceNorm ) > tol )
5616 return true; // not on face plane
5618 // check if point is out of face boundary:
5619 // define it by closest transition of a ray point->infinity through face boundary
5620 // on the face plane.
5621 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
5622 // to find intersections of the ray with the boundary.
5624 gp_Vec plnNorm = ray ^ faceNorm;
5625 normSize = plnNorm.Magnitude();
5626 if ( normSize <= tol ) return false; // point coincides with the first node
5627 plnNorm /= normSize;
5628 // for each node of the face, compute its signed distance to the plane
5629 vector<double> dist( nbNodes + 1);
5630 for ( i = 0; i < nbNodes; ++i )
5632 gp_Vec n2p( xyz[i], point );
5633 dist[i] = n2p * plnNorm;
5635 dist.back() = dist.front();
5636 // find the closest intersection
5638 double rClosest, distClosest = 1e100;;
5640 for ( i = 0; i < nbNodes; ++i )
5643 if ( dist[i] < tol )
5645 else if ( dist[i+1] < tol )
5647 else if ( dist[i] * dist[i+1] < 0 )
5648 r = dist[i] / ( dist[i] - dist[i+1] );
5650 continue; // no intersection
5651 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
5652 gp_Vec p2int ( point, pInt);
5653 if ( p2int * ray > -tol ) // right half-space
5655 double intDist = p2int.SquareMagnitude();
5656 if ( intDist < distClosest )
5661 distClosest = intDist;
5666 return true; // no intesections - out
5668 // analyse transition
5669 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
5670 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
5671 gp_Vec p2int ( point, pClosest );
5672 bool out = (edgeNorm * p2int) < -tol;
5673 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
5676 // ray pass through a face node; analyze transition through an adjacent edge
5677 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
5678 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
5679 gp_Vec edgeAdjacent( p1, p2 );
5680 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
5681 bool out2 = (edgeNorm2 * p2int) < -tol;
5683 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
5684 return covexCorner ? (out || out2) : (out && out2);
5686 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
5688 // point is out of edge if it is NOT ON any straight part of edge
5689 // (we consider quadratic edge as being composed of two straight parts)
5690 for ( i = 1; i < nbNodes; ++i )
5692 gp_Vec edge( xyz[i-1], xyz[i]);
5693 gp_Vec n1p ( xyz[i-1], point);
5694 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
5697 gp_Vec n2p( xyz[i], point );
5698 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
5700 return false; // point is ON this part
5704 // Node or 0D element -------------------------------------------------------------------------
5706 gp_Vec n2p ( xyz[0], point );
5707 return n2p.Magnitude() <= tol;
5712 //=======================================================================
5713 //function : SimplifyFace
5715 //=======================================================================
5716 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5717 vector<const SMDS_MeshNode *>& poly_nodes,
5718 vector<int>& quantities) const
5720 int nbNodes = faceNodes.size();
5725 set<const SMDS_MeshNode*> nodeSet;
5727 // get simple seq of nodes
5728 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5729 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5730 int iSimple = 0, nbUnique = 0;
5732 simpleNodes[iSimple++] = faceNodes[0];
5734 for (int iCur = 1; iCur < nbNodes; iCur++) {
5735 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5736 simpleNodes[iSimple++] = faceNodes[iCur];
5737 if (nodeSet.insert( faceNodes[iCur] ).second)
5741 int nbSimple = iSimple;
5742 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5752 bool foundLoop = (nbSimple > nbUnique);
5755 set<const SMDS_MeshNode*> loopSet;
5756 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5757 const SMDS_MeshNode* n = simpleNodes[iSimple];
5758 if (!loopSet.insert( n ).second) {
5762 int iC = 0, curLast = iSimple;
5763 for (; iC < curLast; iC++) {
5764 if (simpleNodes[iC] == n) break;
5766 int loopLen = curLast - iC;
5768 // create sub-element
5770 quantities.push_back(loopLen);
5771 for (; iC < curLast; iC++) {
5772 poly_nodes.push_back(simpleNodes[iC]);
5775 // shift the rest nodes (place from the first loop position)
5776 for (iC = curLast + 1; iC < nbSimple; iC++) {
5777 simpleNodes[iC - loopLen] = simpleNodes[iC];
5779 nbSimple -= loopLen;
5782 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5783 } // while (foundLoop)
5787 quantities.push_back(iSimple);
5788 for (int i = 0; i < iSimple; i++)
5789 poly_nodes.push_back(simpleNodes[i]);
5795 //=======================================================================
5796 //function : MergeNodes
5797 //purpose : In each group, the cdr of nodes are substituted by the first one
5799 //=======================================================================
5801 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5803 myLastCreatedElems.Clear();
5804 myLastCreatedNodes.Clear();
5806 SMESHDS_Mesh* aMesh = GetMeshDS();
5808 TNodeNodeMap nodeNodeMap; // node to replace - new node
5809 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5810 list< int > rmElemIds, rmNodeIds;
5812 // Fill nodeNodeMap and elems
5814 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5815 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5816 list<const SMDS_MeshNode*>& nodes = *grIt;
5817 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5818 const SMDS_MeshNode* nToKeep = *nIt;
5819 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5820 const SMDS_MeshNode* nToRemove = *nIt;
5821 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5822 if ( nToRemove != nToKeep ) {
5823 rmNodeIds.push_back( nToRemove->GetID() );
5824 AddToSameGroups( nToKeep, nToRemove, aMesh );
5827 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5828 while ( invElemIt->more() ) {
5829 const SMDS_MeshElement* elem = invElemIt->next();
5834 // Change element nodes or remove an element
5836 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5837 for ( ; eIt != elems.end(); eIt++ ) {
5838 const SMDS_MeshElement* elem = *eIt;
5839 int nbNodes = elem->NbNodes();
5840 int aShapeId = FindShape( elem );
5842 set<const SMDS_MeshNode*> nodeSet;
5843 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5844 int iUnique = 0, iCur = 0, nbRepl = 0;
5845 vector<int> iRepl( nbNodes );
5847 // get new seq of nodes
5848 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5849 while ( itN->more() ) {
5850 const SMDS_MeshNode* n =
5851 static_cast<const SMDS_MeshNode*>( itN->next() );
5853 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5854 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5856 // BUG 0020185: begin
5858 bool stopRecur = false;
5859 set<const SMDS_MeshNode*> nodesRecur;
5860 nodesRecur.insert(n);
5861 while (!stopRecur) {
5862 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5863 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5864 n = (*nnIt_i).second;
5865 if (!nodesRecur.insert(n).second) {
5866 // error: recursive dependancy
5875 iRepl[ nbRepl++ ] = iCur;
5877 curNodes[ iCur ] = n;
5878 bool isUnique = nodeSet.insert( n ).second;
5880 uniqueNodes[ iUnique++ ] = n;
5884 // Analyse element topology after replacement
5887 int nbUniqueNodes = nodeSet.size();
5888 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5889 // Polygons and Polyhedral volumes
5890 if (elem->IsPoly()) {
5892 if (elem->GetType() == SMDSAbs_Face) {
5894 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5896 for (; inode < nbNodes; inode++) {
5897 face_nodes[inode] = curNodes[inode];
5900 vector<const SMDS_MeshNode *> polygons_nodes;
5901 vector<int> quantities;
5902 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5906 for (int iface = 0; iface < nbNew - 1; iface++) {
5907 int nbNodes = quantities[iface];
5908 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5909 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5910 poly_nodes[ii] = polygons_nodes[inode];
5912 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5913 myLastCreatedElems.Append(newElem);
5915 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5917 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5920 rmElemIds.push_back(elem->GetID());
5924 else if (elem->GetType() == SMDSAbs_Volume) {
5925 // Polyhedral volume
5926 if (nbUniqueNodes < 4) {
5927 rmElemIds.push_back(elem->GetID());
5930 // each face has to be analized in order to check volume validity
5931 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5932 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5934 int nbFaces = aPolyedre->NbFaces();
5936 vector<const SMDS_MeshNode *> poly_nodes;
5937 vector<int> quantities;
5939 for (int iface = 1; iface <= nbFaces; iface++) {
5940 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5941 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5943 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5944 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5945 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5946 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5947 faceNode = (*nnIt).second;
5949 faceNodes[inode - 1] = faceNode;
5952 SimplifyFace(faceNodes, poly_nodes, quantities);
5955 if (quantities.size() > 3) {
5956 // to be done: remove coincident faces
5959 if (quantities.size() > 3)
5960 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5962 rmElemIds.push_back(elem->GetID());
5966 rmElemIds.push_back(elem->GetID());
5977 switch ( nbNodes ) {
5978 case 2: ///////////////////////////////////// EDGE
5979 isOk = false; break;
5980 case 3: ///////////////////////////////////// TRIANGLE
5981 isOk = false; break;
5983 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5985 else { //////////////////////////////////// QUADRANGLE
5986 if ( nbUniqueNodes < 3 )
5988 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5989 isOk = false; // opposite nodes stick
5992 case 6: ///////////////////////////////////// PENTAHEDRON
5993 if ( nbUniqueNodes == 4 ) {
5994 // ---------------------------------> tetrahedron
5996 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5997 // all top nodes stick: reverse a bottom
5998 uniqueNodes[ 0 ] = curNodes [ 1 ];
5999 uniqueNodes[ 1 ] = curNodes [ 0 ];
6001 else if (nbRepl == 3 &&
6002 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6003 // all bottom nodes stick: set a top before
6004 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6005 uniqueNodes[ 0 ] = curNodes [ 3 ];
6006 uniqueNodes[ 1 ] = curNodes [ 4 ];
6007 uniqueNodes[ 2 ] = curNodes [ 5 ];
6009 else if (nbRepl == 4 &&
6010 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6011 // a lateral face turns into a line: reverse a bottom
6012 uniqueNodes[ 0 ] = curNodes [ 1 ];
6013 uniqueNodes[ 1 ] = curNodes [ 0 ];
6018 else if ( nbUniqueNodes == 5 ) {
6019 // PENTAHEDRON --------------------> 2 tetrahedrons
6020 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6021 // a bottom node sticks with a linked top one
6023 SMDS_MeshElement* newElem =
6024 aMesh->AddVolume(curNodes[ 3 ],
6027 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6028 myLastCreatedElems.Append(newElem);
6030 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6031 // 2. : reverse a bottom
6032 uniqueNodes[ 0 ] = curNodes [ 1 ];
6033 uniqueNodes[ 1 ] = curNodes [ 0 ];
6043 if(elem->IsQuadratic()) { // Quadratic quadrangle
6056 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6057 uniqueNodes[0] = curNodes[0];
6058 uniqueNodes[1] = curNodes[2];
6059 uniqueNodes[2] = curNodes[3];
6060 uniqueNodes[3] = curNodes[5];
6061 uniqueNodes[4] = curNodes[6];
6062 uniqueNodes[5] = curNodes[7];
6065 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6066 uniqueNodes[0] = curNodes[0];
6067 uniqueNodes[1] = curNodes[1];
6068 uniqueNodes[2] = curNodes[2];
6069 uniqueNodes[3] = curNodes[4];
6070 uniqueNodes[4] = curNodes[5];
6071 uniqueNodes[5] = curNodes[6];
6074 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6075 uniqueNodes[0] = curNodes[1];
6076 uniqueNodes[1] = curNodes[2];
6077 uniqueNodes[2] = curNodes[3];
6078 uniqueNodes[3] = curNodes[5];
6079 uniqueNodes[4] = curNodes[6];
6080 uniqueNodes[5] = curNodes[0];
6083 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6084 uniqueNodes[0] = curNodes[0];
6085 uniqueNodes[1] = curNodes[1];
6086 uniqueNodes[2] = curNodes[3];
6087 uniqueNodes[3] = curNodes[4];
6088 uniqueNodes[4] = curNodes[6];
6089 uniqueNodes[5] = curNodes[7];
6092 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6093 uniqueNodes[0] = curNodes[0];
6094 uniqueNodes[1] = curNodes[2];
6095 uniqueNodes[2] = curNodes[3];
6096 uniqueNodes[3] = curNodes[1];
6097 uniqueNodes[4] = curNodes[6];
6098 uniqueNodes[5] = curNodes[7];
6101 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6102 uniqueNodes[0] = curNodes[0];
6103 uniqueNodes[1] = curNodes[1];
6104 uniqueNodes[2] = curNodes[2];
6105 uniqueNodes[3] = curNodes[4];
6106 uniqueNodes[4] = curNodes[5];
6107 uniqueNodes[5] = curNodes[7];
6110 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6111 uniqueNodes[0] = curNodes[0];
6112 uniqueNodes[1] = curNodes[1];
6113 uniqueNodes[2] = curNodes[3];
6114 uniqueNodes[3] = curNodes[4];
6115 uniqueNodes[4] = curNodes[2];
6116 uniqueNodes[5] = curNodes[7];
6119 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6120 uniqueNodes[0] = curNodes[0];
6121 uniqueNodes[1] = curNodes[1];
6122 uniqueNodes[2] = curNodes[2];
6123 uniqueNodes[3] = curNodes[4];
6124 uniqueNodes[4] = curNodes[5];
6125 uniqueNodes[5] = curNodes[3];
6131 //////////////////////////////////// HEXAHEDRON
6133 SMDS_VolumeTool hexa (elem);
6134 hexa.SetExternalNormal();
6135 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6136 //////////////////////// ---> tetrahedron
6137 for ( int iFace = 0; iFace < 6; iFace++ ) {
6138 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6139 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6140 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6141 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6142 // one face turns into a point ...
6143 int iOppFace = hexa.GetOppFaceIndex( iFace );
6144 ind = hexa.GetFaceNodesIndices( iOppFace );
6146 iUnique = 2; // reverse a tetrahedron bottom
6147 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6148 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6150 else if ( iUnique >= 0 )
6151 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6153 if ( nbStick == 1 ) {
6154 // ... and the opposite one - into a triangle.
6156 ind = hexa.GetFaceNodesIndices( iFace );
6157 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6164 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6165 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6166 for ( int iFace = 0; iFace < 6; iFace++ ) {
6167 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6168 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6169 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6170 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6171 // one face turns into a point ...
6172 int iOppFace = hexa.GetOppFaceIndex( iFace );
6173 ind = hexa.GetFaceNodesIndices( iOppFace );
6175 iUnique = 2; // reverse a tetrahedron 1 bottom
6176 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6177 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6179 else if ( iUnique >= 0 )
6180 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6182 if ( nbStick == 0 ) {
6183 // ... and the opposite one is a quadrangle
6185 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6186 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6189 SMDS_MeshElement* newElem =
6190 aMesh->AddVolume(curNodes[ind[ 0 ]],
6193 curNodes[indTop[ 0 ]]);
6194 myLastCreatedElems.Append(newElem);
6196 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6203 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6204 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6205 // find indices of quad and tri faces
6206 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6207 for ( iFace = 0; iFace < 6; iFace++ ) {
6208 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6210 for ( iCur = 0; iCur < 4; iCur++ )
6211 nodeSet.insert( curNodes[ind[ iCur ]] );
6212 nbUniqueNodes = nodeSet.size();
6213 if ( nbUniqueNodes == 3 )
6214 iTriFace[ nbTri++ ] = iFace;
6215 else if ( nbUniqueNodes == 4 )
6216 iQuadFace[ nbQuad++ ] = iFace;
6218 if (nbQuad == 2 && nbTri == 4 &&
6219 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6220 // 2 opposite quadrangles stuck with a diagonal;
6221 // sample groups of merged indices: (0-4)(2-6)
6222 // --------------------------------------------> 2 tetrahedrons
6223 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6224 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6225 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6226 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6227 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6228 // stuck with 0-2 diagonal
6236 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6237 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6238 // stuck with 1-3 diagonal
6250 uniqueNodes[ 0 ] = curNodes [ i0 ];
6251 uniqueNodes[ 1 ] = curNodes [ i1d ];
6252 uniqueNodes[ 2 ] = curNodes [ i3d ];
6253 uniqueNodes[ 3 ] = curNodes [ i0t ];
6256 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6260 myLastCreatedElems.Append(newElem);
6262 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6265 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6266 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6267 // --------------------------------------------> prism
6268 // find 2 opposite triangles
6270 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6271 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6272 // find indices of kept and replaced nodes
6273 // and fill unique nodes of 2 opposite triangles
6274 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6275 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6276 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6277 // fill unique nodes
6280 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6281 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
6282 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6284 // iCur of a linked node of the opposite face (make normals co-directed):
6285 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6286 // check that correspondent corners of triangles are linked
6287 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6290 uniqueNodes[ iUnique ] = n;
6291 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6300 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6306 } // switch ( nbNodes )
6308 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6311 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
6312 // Change nodes of polyedre
6313 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6314 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6316 int nbFaces = aPolyedre->NbFaces();
6318 vector<const SMDS_MeshNode *> poly_nodes;
6319 vector<int> quantities (nbFaces);
6321 for (int iface = 1; iface <= nbFaces; iface++) {
6322 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6323 quantities[iface - 1] = nbFaceNodes;
6325 for (inode = 1; inode <= nbFaceNodes; inode++) {
6326 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6328 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6329 if (nnIt != nodeNodeMap.end()) { // curNode sticks
6330 curNode = (*nnIt).second;
6332 poly_nodes.push_back(curNode);
6335 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6339 // Change regular element or polygon
6340 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
6344 // Remove invalid regular element or invalid polygon
6345 rmElemIds.push_back( elem->GetID() );
6348 } // loop on elements
6350 // Remove equal nodes and bad elements
6352 Remove( rmNodeIds, true );
6353 Remove( rmElemIds, false );
6358 // ========================================================
6359 // class : SortableElement
6360 // purpose : allow sorting elements basing on their nodes
6361 // ========================================================
6362 class SortableElement : public set <const SMDS_MeshElement*>
6366 SortableElement( const SMDS_MeshElement* theElem )
6369 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6370 while ( nodeIt->more() )
6371 this->insert( nodeIt->next() );
6374 const SMDS_MeshElement* Get() const
6377 void Set(const SMDS_MeshElement* e) const
6382 mutable const SMDS_MeshElement* myElem;
6385 //=======================================================================
6386 //function : FindEqualElements
6387 //purpose : Return list of group of elements built on the same nodes.
6388 // Search among theElements or in the whole mesh if theElements is empty
6389 //=======================================================================
6390 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
6391 TListOfListOfElementsID & theGroupsOfElementsID)
6393 myLastCreatedElems.Clear();
6394 myLastCreatedNodes.Clear();
6396 typedef set<const SMDS_MeshElement*> TElemsSet;
6397 typedef map< SortableElement, int > TMapOfNodeSet;
6398 typedef list<int> TGroupOfElems;
6401 if ( theElements.empty() )
6402 { // get all elements in the mesh
6403 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
6404 while ( eIt->more() )
6405 elems.insert( elems.end(), eIt->next());
6408 elems = theElements;
6410 vector< TGroupOfElems > arrayOfGroups;
6411 TGroupOfElems groupOfElems;
6412 TMapOfNodeSet mapOfNodeSet;
6414 TElemsSet::iterator elemIt = elems.begin();
6415 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
6416 const SMDS_MeshElement* curElem = *elemIt;
6417 SortableElement SE(curElem);
6420 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
6421 if( !(pp.second) ) {
6422 TMapOfNodeSet::iterator& itSE = pp.first;
6423 ind = (*itSE).second;
6424 arrayOfGroups[ind].push_back(curElem->GetID());
6427 groupOfElems.clear();
6428 groupOfElems.push_back(curElem->GetID());
6429 arrayOfGroups.push_back(groupOfElems);
6434 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
6435 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
6436 groupOfElems = *groupIt;
6437 if ( groupOfElems.size() > 1 ) {
6438 groupOfElems.sort();
6439 theGroupsOfElementsID.push_back(groupOfElems);
6444 //=======================================================================
6445 //function : MergeElements
6446 //purpose : In each given group, substitute all elements by the first one.
6447 //=======================================================================
6449 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
6451 myLastCreatedElems.Clear();
6452 myLastCreatedNodes.Clear();
6454 typedef list<int> TListOfIDs;
6455 TListOfIDs rmElemIds; // IDs of elems to remove
6457 SMESHDS_Mesh* aMesh = GetMeshDS();
6459 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
6460 while ( groupsIt != theGroupsOfElementsID.end() ) {
6461 TListOfIDs& aGroupOfElemID = *groupsIt;
6462 aGroupOfElemID.sort();
6463 int elemIDToKeep = aGroupOfElemID.front();
6464 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
6465 aGroupOfElemID.pop_front();
6466 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
6467 while ( idIt != aGroupOfElemID.end() ) {
6468 int elemIDToRemove = *idIt;
6469 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
6470 // add the kept element in groups of removed one (PAL15188)
6471 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
6472 rmElemIds.push_back( elemIDToRemove );
6478 Remove( rmElemIds, false );
6481 //=======================================================================
6482 //function : MergeEqualElements
6483 //purpose : Remove all but one of elements built on the same nodes.
6484 //=======================================================================
6486 void SMESH_MeshEditor::MergeEqualElements()
6488 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
6489 to merge equal elements in the whole mesh */
6490 TListOfListOfElementsID aGroupsOfElementsID;
6491 FindEqualElements(aMeshElements, aGroupsOfElementsID);
6492 MergeElements(aGroupsOfElementsID);
6495 //=======================================================================
6496 //function : FindFaceInSet
6497 //purpose : Return a face having linked nodes n1 and n2 and which is
6498 // - not in avoidSet,
6499 // - in elemSet provided that !elemSet.empty()
6500 //=======================================================================
6502 const SMDS_MeshElement*
6503 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
6504 const SMDS_MeshNode* n2,
6505 const TIDSortedElemSet& elemSet,
6506 const TIDSortedElemSet& avoidSet)
6509 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
6510 while ( invElemIt->more() ) { // loop on inverse elements of n1
6511 const SMDS_MeshElement* elem = invElemIt->next();
6512 if (avoidSet.find( elem ) != avoidSet.end() )
6514 if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
6516 // get face nodes and find index of n1
6517 int i1, nbN = elem->NbNodes(), iNode = 0;
6518 //const SMDS_MeshNode* faceNodes[ nbN ], *n;
6519 vector<const SMDS_MeshNode*> faceNodes( nbN );
6520 const SMDS_MeshNode* n;
6521 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6522 while ( nIt->more() ) {
6523 faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6524 if ( faceNodes[ iNode++ ] == n1 )
6527 // find a n2 linked to n1
6528 if(!elem->IsQuadratic()) {
6529 for ( iNode = 0; iNode < 2; iNode++ ) {
6530 if ( iNode ) // node before n1
6531 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6532 else // node after n1
6533 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6538 else { // analysis for quadratic elements
6539 bool IsFind = false;
6540 // check using only corner nodes
6541 for ( iNode = 0; iNode < 2; iNode++ ) {
6542 if ( iNode ) // node before n1
6543 n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
6544 else // node after n1
6545 n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
6553 // check using all nodes
6554 const SMDS_QuadraticFaceOfNodes* F =
6555 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6556 // use special nodes iterator
6558 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6559 while ( anIter->more() ) {
6560 faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
6561 if ( faceNodes[ iNode++ ] == n1 )
6564 for ( iNode = 0; iNode < 2; iNode++ ) {
6565 if ( iNode ) // node before n1
6566 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6567 else // node after n1
6568 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6574 } // end analysis for quadratic elements
6579 //=======================================================================
6580 //function : findAdjacentFace
6582 //=======================================================================
6584 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6585 const SMDS_MeshNode* n2,
6586 const SMDS_MeshElement* elem)
6588 TIDSortedElemSet elemSet, avoidSet;
6590 avoidSet.insert ( elem );
6591 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6594 //=======================================================================
6595 //function : FindFreeBorder
6597 //=======================================================================
6599 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6601 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
6602 const SMDS_MeshNode* theSecondNode,
6603 const SMDS_MeshNode* theLastNode,
6604 list< const SMDS_MeshNode* > & theNodes,
6605 list< const SMDS_MeshElement* >& theFaces)
6607 if ( !theFirstNode || !theSecondNode )
6609 // find border face between theFirstNode and theSecondNode
6610 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6614 theFaces.push_back( curElem );
6615 theNodes.push_back( theFirstNode );
6616 theNodes.push_back( theSecondNode );
6618 //vector<const SMDS_MeshNode*> nodes;
6619 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6620 TIDSortedElemSet foundElems;
6621 bool needTheLast = ( theLastNode != 0 );
6623 while ( nStart != theLastNode ) {
6624 if ( nStart == theFirstNode )
6625 return !needTheLast;
6627 // find all free border faces sharing form nStart
6629 list< const SMDS_MeshElement* > curElemList;
6630 list< const SMDS_MeshNode* > nStartList;
6631 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6632 while ( invElemIt->more() ) {
6633 const SMDS_MeshElement* e = invElemIt->next();
6634 if ( e == curElem || foundElems.insert( e ).second ) {
6636 int iNode = 0, nbNodes = e->NbNodes();
6637 //const SMDS_MeshNode* nodes[nbNodes+1];
6638 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6640 if(e->IsQuadratic()) {
6641 const SMDS_QuadraticFaceOfNodes* F =
6642 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6643 // use special nodes iterator
6644 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6645 while( anIter->more() ) {
6646 nodes[ iNode++ ] = anIter->next();
6650 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6651 while ( nIt->more() )
6652 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6654 nodes[ iNode ] = nodes[ 0 ];
6656 for ( iNode = 0; iNode < nbNodes; iNode++ )
6657 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6658 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6659 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6661 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6662 curElemList.push_back( e );
6666 // analyse the found
6668 int nbNewBorders = curElemList.size();
6669 if ( nbNewBorders == 0 ) {
6670 // no free border furthermore
6671 return !needTheLast;
6673 else if ( nbNewBorders == 1 ) {
6674 // one more element found
6676 nStart = nStartList.front();
6677 curElem = curElemList.front();
6678 theFaces.push_back( curElem );
6679 theNodes.push_back( nStart );
6682 // several continuations found
6683 list< const SMDS_MeshElement* >::iterator curElemIt;
6684 list< const SMDS_MeshNode* >::iterator nStartIt;
6685 // check if one of them reached the last node
6686 if ( needTheLast ) {
6687 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6688 curElemIt!= curElemList.end();
6689 curElemIt++, nStartIt++ )
6690 if ( *nStartIt == theLastNode ) {
6691 theFaces.push_back( *curElemIt );
6692 theNodes.push_back( *nStartIt );
6696 // find the best free border by the continuations
6697 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6698 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6699 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6700 curElemIt!= curElemList.end();
6701 curElemIt++, nStartIt++ )
6703 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6704 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6705 // find one more free border
6706 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6710 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6711 // choice: clear a worse one
6712 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6713 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6714 contNodes[ iWorse ].clear();
6715 contFaces[ iWorse ].clear();
6718 if ( contNodes[0].empty() && contNodes[1].empty() )
6721 // append the best free border
6722 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6723 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6724 theNodes.pop_back(); // remove nIgnore
6725 theNodes.pop_back(); // remove nStart
6726 theFaces.pop_back(); // remove curElem
6727 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6728 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6729 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6730 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6733 } // several continuations found
6734 } // while ( nStart != theLastNode )
6739 //=======================================================================
6740 //function : CheckFreeBorderNodes
6741 //purpose : Return true if the tree nodes are on a free border
6742 //=======================================================================
6744 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6745 const SMDS_MeshNode* theNode2,
6746 const SMDS_MeshNode* theNode3)
6748 list< const SMDS_MeshNode* > nodes;
6749 list< const SMDS_MeshElement* > faces;
6750 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6753 //=======================================================================
6754 //function : SewFreeBorder
6756 //=======================================================================
6758 SMESH_MeshEditor::Sew_Error
6759 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6760 const SMDS_MeshNode* theBordSecondNode,
6761 const SMDS_MeshNode* theBordLastNode,
6762 const SMDS_MeshNode* theSideFirstNode,
6763 const SMDS_MeshNode* theSideSecondNode,
6764 const SMDS_MeshNode* theSideThirdNode,
6765 const bool theSideIsFreeBorder,
6766 const bool toCreatePolygons,
6767 const bool toCreatePolyedrs)
6769 myLastCreatedElems.Clear();
6770 myLastCreatedNodes.Clear();
6772 MESSAGE("::SewFreeBorder()");
6773 Sew_Error aResult = SEW_OK;
6775 // ====================================
6776 // find side nodes and elements
6777 // ====================================
6779 list< const SMDS_MeshNode* > nSide[ 2 ];
6780 list< const SMDS_MeshElement* > eSide[ 2 ];
6781 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6782 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6786 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6787 nSide[0], eSide[0])) {
6788 MESSAGE(" Free Border 1 not found " );
6789 aResult = SEW_BORDER1_NOT_FOUND;
6791 if (theSideIsFreeBorder) {
6794 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6795 nSide[1], eSide[1])) {
6796 MESSAGE(" Free Border 2 not found " );
6797 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6800 if ( aResult != SEW_OK )
6803 if (!theSideIsFreeBorder) {
6807 // -------------------------------------------------------------------------
6809 // 1. If nodes to merge are not coincident, move nodes of the free border
6810 // from the coord sys defined by the direction from the first to last
6811 // nodes of the border to the correspondent sys of the side 2
6812 // 2. On the side 2, find the links most co-directed with the correspondent
6813 // links of the free border
6814 // -------------------------------------------------------------------------
6816 // 1. Since sewing may brake if there are volumes to split on the side 2,
6817 // we wont move nodes but just compute new coordinates for them
6818 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6819 TNodeXYZMap nBordXYZ;
6820 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6821 list< const SMDS_MeshNode* >::iterator nBordIt;
6823 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6824 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6825 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6826 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6827 double tol2 = 1.e-8;
6828 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6829 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6830 // Need node movement.
6832 // find X and Z axes to create trsf
6833 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6835 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6837 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6840 gp_Ax3 toBordAx( Pb1, Zb, X );
6841 gp_Ax3 fromSideAx( Ps1, Zs, X );
6842 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6844 gp_Trsf toBordSys, fromSide2Sys;
6845 toBordSys.SetTransformation( toBordAx );
6846 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6847 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6850 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6851 const SMDS_MeshNode* n = *nBordIt;
6852 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6853 toBordSys.Transforms( xyz );
6854 fromSide2Sys.Transforms( xyz );
6855 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6859 // just insert nodes XYZ in the nBordXYZ map
6860 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6861 const SMDS_MeshNode* n = *nBordIt;
6862 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6866 // 2. On the side 2, find the links most co-directed with the correspondent
6867 // links of the free border
6869 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6870 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6871 sideNodes.push_back( theSideFirstNode );
6873 bool hasVolumes = false;
6874 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6875 set<long> foundSideLinkIDs, checkedLinkIDs;
6876 SMDS_VolumeTool volume;
6877 //const SMDS_MeshNode* faceNodes[ 4 ];
6879 const SMDS_MeshNode* sideNode;
6880 const SMDS_MeshElement* sideElem;
6881 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6882 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6883 nBordIt = bordNodes.begin();
6885 // border node position and border link direction to compare with
6886 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6887 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6888 // choose next side node by link direction or by closeness to
6889 // the current border node:
6890 bool searchByDir = ( *nBordIt != theBordLastNode );
6892 // find the next node on the Side 2
6894 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6896 checkedLinkIDs.clear();
6897 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6899 // loop on inverse elements of current node (prevSideNode) on the Side 2
6900 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6901 while ( invElemIt->more() )
6903 const SMDS_MeshElement* elem = invElemIt->next();
6904 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6905 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6906 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6907 bool isVolume = volume.Set( elem );
6908 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6909 if ( isVolume ) // --volume
6911 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6912 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6913 if(elem->IsQuadratic()) {
6914 const SMDS_QuadraticFaceOfNodes* F =
6915 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6916 // use special nodes iterator
6917 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6918 while( anIter->more() ) {
6919 nodes[ iNode ] = anIter->next();
6920 if ( nodes[ iNode++ ] == prevSideNode )
6921 iPrevNode = iNode - 1;
6925 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6926 while ( nIt->more() ) {
6927 nodes[ iNode ] = cast2Node( nIt->next() );
6928 if ( nodes[ iNode++ ] == prevSideNode )
6929 iPrevNode = iNode - 1;
6932 // there are 2 links to check
6937 // loop on links, to be precise, on the second node of links
6938 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6939 const SMDS_MeshNode* n = nodes[ iNode ];
6941 if ( !volume.IsLinked( n, prevSideNode ))
6945 if ( iNode ) // a node before prevSideNode
6946 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6947 else // a node after prevSideNode
6948 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6950 // check if this link was already used
6951 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6952 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6953 if (!isJustChecked &&
6954 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6956 // test a link geometrically
6957 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6958 bool linkIsBetter = false;
6959 double dot = 0.0, dist = 0.0;
6960 if ( searchByDir ) { // choose most co-directed link
6961 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6962 linkIsBetter = ( dot > maxDot );
6964 else { // choose link with the node closest to bordPos
6965 dist = ( nextXYZ - bordPos ).SquareModulus();
6966 linkIsBetter = ( dist < minDist );
6968 if ( linkIsBetter ) {
6977 } // loop on inverse elements of prevSideNode
6980 MESSAGE(" Cant find path by links of the Side 2 ");
6981 return SEW_BAD_SIDE_NODES;
6983 sideNodes.push_back( sideNode );
6984 sideElems.push_back( sideElem );
6985 foundSideLinkIDs.insert ( linkID );
6986 prevSideNode = sideNode;
6988 if ( *nBordIt == theBordLastNode )
6989 searchByDir = false;
6991 // find the next border link to compare with
6992 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6993 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6994 // move to next border node if sideNode is before forward border node (bordPos)
6995 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6996 prevBordNode = *nBordIt;
6998 bordPos = nBordXYZ[ *nBordIt ];
6999 bordDir = bordPos - nBordXYZ[ prevBordNode ];
7000 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7004 while ( sideNode != theSideSecondNode );
7006 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7007 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7008 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7010 } // end nodes search on the side 2
7012 // ============================
7013 // sew the border to the side 2
7014 // ============================
7016 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
7017 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7019 TListOfListOfNodes nodeGroupsToMerge;
7020 if ( nbNodes[0] == nbNodes[1] ||
7021 ( theSideIsFreeBorder && !theSideThirdNode)) {
7023 // all nodes are to be merged
7025 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7026 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7027 nIt[0]++, nIt[1]++ )
7029 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7030 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7031 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7036 // insert new nodes into the border and the side to get equal nb of segments
7038 // get normalized parameters of nodes on the borders
7039 //double param[ 2 ][ maxNbNodes ];
7041 param[0] = new double [ maxNbNodes ];
7042 param[1] = new double [ maxNbNodes ];
7044 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7045 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7046 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7047 const SMDS_MeshNode* nPrev = *nIt;
7048 double bordLength = 0;
7049 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7050 const SMDS_MeshNode* nCur = *nIt;
7051 gp_XYZ segment (nCur->X() - nPrev->X(),
7052 nCur->Y() - nPrev->Y(),
7053 nCur->Z() - nPrev->Z());
7054 double segmentLen = segment.Modulus();
7055 bordLength += segmentLen;
7056 param[ iBord ][ iNode ] = bordLength;
7059 // normalize within [0,1]
7060 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7061 param[ iBord ][ iNode ] /= bordLength;
7065 // loop on border segments
7066 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7067 int i[ 2 ] = { 0, 0 };
7068 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7069 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7071 TElemOfNodeListMap insertMap;
7072 TElemOfNodeListMap::iterator insertMapIt;
7074 // key: elem to insert nodes into
7075 // value: 2 nodes to insert between + nodes to be inserted
7077 bool next[ 2 ] = { false, false };
7079 // find min adjacent segment length after sewing
7080 double nextParam = 10., prevParam = 0;
7081 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7082 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7083 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7084 if ( i[ iBord ] > 0 )
7085 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7087 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7088 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7089 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7091 // choose to insert or to merge nodes
7092 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7093 if ( Abs( du ) <= minSegLen * 0.2 ) {
7096 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7097 const SMDS_MeshNode* n0 = *nIt[0];
7098 const SMDS_MeshNode* n1 = *nIt[1];
7099 nodeGroupsToMerge.back().push_back( n1 );
7100 nodeGroupsToMerge.back().push_back( n0 );
7101 // position of node of the border changes due to merge
7102 param[ 0 ][ i[0] ] += du;
7103 // move n1 for the sake of elem shape evaluation during insertion.
7104 // n1 will be removed by MergeNodes() anyway
7105 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7106 next[0] = next[1] = true;
7111 int intoBord = ( du < 0 ) ? 0 : 1;
7112 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7113 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7114 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7115 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7116 if ( intoBord == 1 ) {
7117 // move node of the border to be on a link of elem of the side
7118 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7119 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7120 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7121 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7122 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7124 insertMapIt = insertMap.find( elem );
7125 bool notFound = ( insertMapIt == insertMap.end() );
7126 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7128 // insert into another link of the same element:
7129 // 1. perform insertion into the other link of the elem
7130 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7131 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7132 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7133 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7134 // 2. perform insertion into the link of adjacent faces
7136 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7138 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7142 if (toCreatePolyedrs) {
7143 // perform insertion into the links of adjacent volumes
7144 UpdateVolumes(n12, n22, nodeList);
7146 // 3. find an element appeared on n1 and n2 after the insertion
7147 insertMap.erase( elem );
7148 elem = findAdjacentFace( n1, n2, 0 );
7150 if ( notFound || otherLink ) {
7151 // add element and nodes of the side into the insertMap
7152 insertMapIt = insertMap.insert
7153 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7154 (*insertMapIt).second.push_back( n1 );
7155 (*insertMapIt).second.push_back( n2 );
7157 // add node to be inserted into elem
7158 (*insertMapIt).second.push_back( nIns );
7159 next[ 1 - intoBord ] = true;
7162 // go to the next segment
7163 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7164 if ( next[ iBord ] ) {
7165 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7167 nPrev[ iBord ] = *nIt[ iBord ];
7168 nIt[ iBord ]++; i[ iBord ]++;
7172 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7174 // perform insertion of nodes into elements
7176 for (insertMapIt = insertMap.begin();
7177 insertMapIt != insertMap.end();
7180 const SMDS_MeshElement* elem = (*insertMapIt).first;
7181 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7182 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7183 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7185 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7187 if ( !theSideIsFreeBorder ) {
7188 // look for and insert nodes into the faces adjacent to elem
7190 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7192 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7197 if (toCreatePolyedrs) {
7198 // perform insertion into the links of adjacent volumes
7199 UpdateVolumes(n1, n2, nodeList);
7205 } // end: insert new nodes
7207 MergeNodes ( nodeGroupsToMerge );
7212 //=======================================================================
7213 //function : InsertNodesIntoLink
7214 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7215 // and theBetweenNode2 and split theElement
7216 //=======================================================================
7218 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7219 const SMDS_MeshNode* theBetweenNode1,
7220 const SMDS_MeshNode* theBetweenNode2,
7221 list<const SMDS_MeshNode*>& theNodesToInsert,
7222 const bool toCreatePoly)
7224 if ( theFace->GetType() != SMDSAbs_Face ) return;
7226 // find indices of 2 link nodes and of the rest nodes
7227 int iNode = 0, il1, il2, i3, i4;
7228 il1 = il2 = i3 = i4 = -1;
7229 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7230 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7232 if(theFace->IsQuadratic()) {
7233 const SMDS_QuadraticFaceOfNodes* F =
7234 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7235 // use special nodes iterator
7236 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7237 while( anIter->more() ) {
7238 const SMDS_MeshNode* n = anIter->next();
7239 if ( n == theBetweenNode1 )
7241 else if ( n == theBetweenNode2 )
7247 nodes[ iNode++ ] = n;
7251 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7252 while ( nodeIt->more() ) {
7253 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7254 if ( n == theBetweenNode1 )
7256 else if ( n == theBetweenNode2 )
7262 nodes[ iNode++ ] = n;
7265 if ( il1 < 0 || il2 < 0 || i3 < 0 )
7268 // arrange link nodes to go one after another regarding the face orientation
7269 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7270 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7275 aNodesToInsert.reverse();
7277 // check that not link nodes of a quadrangles are in good order
7278 int nbFaceNodes = theFace->NbNodes();
7279 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7285 if (toCreatePoly || theFace->IsPoly()) {
7288 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7290 // add nodes of face up to first node of link
7293 if(theFace->IsQuadratic()) {
7294 const SMDS_QuadraticFaceOfNodes* F =
7295 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7296 // use special nodes iterator
7297 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7298 while( anIter->more() && !isFLN ) {
7299 const SMDS_MeshNode* n = anIter->next();
7300 poly_nodes[iNode++] = n;
7301 if (n == nodes[il1]) {
7305 // add nodes to insert
7306 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7307 for (; nIt != aNodesToInsert.end(); nIt++) {
7308 poly_nodes[iNode++] = *nIt;
7310 // add nodes of face starting from last node of link
7311 while ( anIter->more() ) {
7312 poly_nodes[iNode++] = anIter->next();
7316 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7317 while ( nodeIt->more() && !isFLN ) {
7318 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7319 poly_nodes[iNode++] = n;
7320 if (n == nodes[il1]) {
7324 // add nodes to insert
7325 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7326 for (; nIt != aNodesToInsert.end(); nIt++) {
7327 poly_nodes[iNode++] = *nIt;
7329 // add nodes of face starting from last node of link
7330 while ( nodeIt->more() ) {
7331 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7332 poly_nodes[iNode++] = n;
7336 // edit or replace the face
7337 SMESHDS_Mesh *aMesh = GetMeshDS();
7339 if (theFace->IsPoly()) {
7340 aMesh->ChangePolygonNodes(theFace, poly_nodes);
7343 int aShapeId = FindShape( theFace );
7345 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7346 myLastCreatedElems.Append(newElem);
7347 if ( aShapeId && newElem )
7348 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7350 aMesh->RemoveElement(theFace);
7355 if( !theFace->IsQuadratic() ) {
7357 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7358 int nbLinkNodes = 2 + aNodesToInsert.size();
7359 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7360 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7361 linkNodes[ 0 ] = nodes[ il1 ];
7362 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7363 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7364 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7365 linkNodes[ iNode++ ] = *nIt;
7367 // decide how to split a quadrangle: compare possible variants
7368 // and choose which of splits to be a quadrangle
7369 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7370 if ( nbFaceNodes == 3 ) {
7371 iBestQuad = nbSplits;
7374 else if ( nbFaceNodes == 4 ) {
7375 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7376 double aBestRate = DBL_MAX;
7377 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7379 double aBadRate = 0;
7380 // evaluate elements quality
7381 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7382 if ( iSplit == iQuad ) {
7383 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7387 aBadRate += getBadRate( &quad, aCrit );
7390 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7392 nodes[ iSplit < iQuad ? i4 : i3 ]);
7393 aBadRate += getBadRate( &tria, aCrit );
7397 if ( aBadRate < aBestRate ) {
7399 aBestRate = aBadRate;
7404 // create new elements
7405 SMESHDS_Mesh *aMesh = GetMeshDS();
7406 int aShapeId = FindShape( theFace );
7409 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7410 SMDS_MeshElement* newElem = 0;
7411 if ( iSplit == iBestQuad )
7412 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7417 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7419 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7420 myLastCreatedElems.Append(newElem);
7421 if ( aShapeId && newElem )
7422 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7425 // change nodes of theFace
7426 const SMDS_MeshNode* newNodes[ 4 ];
7427 newNodes[ 0 ] = linkNodes[ i1 ];
7428 newNodes[ 1 ] = linkNodes[ i2 ];
7429 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7430 newNodes[ 3 ] = nodes[ i4 ];
7431 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7432 } // end if(!theFace->IsQuadratic())
7433 else { // theFace is quadratic
7434 // we have to split theFace on simple triangles and one simple quadrangle
7436 int nbshift = tmp*2;
7437 // shift nodes in nodes[] by nbshift
7439 for(i=0; i<nbshift; i++) {
7440 const SMDS_MeshNode* n = nodes[0];
7441 for(j=0; j<nbFaceNodes-1; j++) {
7442 nodes[j] = nodes[j+1];
7444 nodes[nbFaceNodes-1] = n;
7446 il1 = il1 - nbshift;
7447 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7448 // n0 n1 n2 n0 n1 n2
7449 // +-----+-----+ +-----+-----+
7458 // create new elements
7459 SMESHDS_Mesh *aMesh = GetMeshDS();
7460 int aShapeId = FindShape( theFace );
7463 if(nbFaceNodes==6) { // quadratic triangle
7464 SMDS_MeshElement* newElem =
7465 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7466 myLastCreatedElems.Append(newElem);
7467 if ( aShapeId && newElem )
7468 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7469 if(theFace->IsMediumNode(nodes[il1])) {
7470 // create quadrangle
7471 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
7472 myLastCreatedElems.Append(newElem);
7473 if ( aShapeId && newElem )
7474 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7480 // create quadrangle
7481 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
7482 myLastCreatedElems.Append(newElem);
7483 if ( aShapeId && newElem )
7484 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7490 else { // nbFaceNodes==8 - quadratic quadrangle
7491 SMDS_MeshElement* newElem =
7492 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7493 myLastCreatedElems.Append(newElem);
7494 if ( aShapeId && newElem )
7495 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7496 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
7497 myLastCreatedElems.Append(newElem);
7498 if ( aShapeId && newElem )
7499 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7500 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
7501 myLastCreatedElems.Append(newElem);
7502 if ( aShapeId && newElem )
7503 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7504 if(theFace->IsMediumNode(nodes[il1])) {
7505 // create quadrangle
7506 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
7507 myLastCreatedElems.Append(newElem);
7508 if ( aShapeId && newElem )
7509 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7515 // create quadrangle
7516 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7517 myLastCreatedElems.Append(newElem);
7518 if ( aShapeId && newElem )
7519 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7525 // create needed triangles using n1,n2,n3 and inserted nodes
7526 int nbn = 2 + aNodesToInsert.size();
7527 //const SMDS_MeshNode* aNodes[nbn];
7528 vector<const SMDS_MeshNode*> aNodes(nbn);
7529 aNodes[0] = nodes[n1];
7530 aNodes[nbn-1] = nodes[n2];
7531 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7532 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7533 aNodes[iNode++] = *nIt;
7535 for(i=1; i<nbn; i++) {
7536 SMDS_MeshElement* newElem =
7537 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7538 myLastCreatedElems.Append(newElem);
7539 if ( aShapeId && newElem )
7540 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7542 // remove old quadratic face
7543 aMesh->RemoveElement(theFace);
7547 //=======================================================================
7548 //function : UpdateVolumes
7550 //=======================================================================
7551 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
7552 const SMDS_MeshNode* theBetweenNode2,
7553 list<const SMDS_MeshNode*>& theNodesToInsert)
7555 myLastCreatedElems.Clear();
7556 myLastCreatedNodes.Clear();
7558 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7559 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7560 const SMDS_MeshElement* elem = invElemIt->next();
7562 // check, if current volume has link theBetweenNode1 - theBetweenNode2
7563 SMDS_VolumeTool aVolume (elem);
7564 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7567 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7568 int iface, nbFaces = aVolume.NbFaces();
7569 vector<const SMDS_MeshNode *> poly_nodes;
7570 vector<int> quantities (nbFaces);
7572 for (iface = 0; iface < nbFaces; iface++) {
7573 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7574 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7575 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7577 for (int inode = 0; inode < nbFaceNodes; inode++) {
7578 poly_nodes.push_back(faceNodes[inode]);
7580 if (nbInserted == 0) {
7581 if (faceNodes[inode] == theBetweenNode1) {
7582 if (faceNodes[inode + 1] == theBetweenNode2) {
7583 nbInserted = theNodesToInsert.size();
7585 // add nodes to insert
7586 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7587 for (; nIt != theNodesToInsert.end(); nIt++) {
7588 poly_nodes.push_back(*nIt);
7592 else if (faceNodes[inode] == theBetweenNode2) {
7593 if (faceNodes[inode + 1] == theBetweenNode1) {
7594 nbInserted = theNodesToInsert.size();
7596 // add nodes to insert in reversed order
7597 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7599 for (; nIt != theNodesToInsert.begin(); nIt--) {
7600 poly_nodes.push_back(*nIt);
7602 poly_nodes.push_back(*nIt);
7609 quantities[iface] = nbFaceNodes + nbInserted;
7612 // Replace or update the volume
7613 SMESHDS_Mesh *aMesh = GetMeshDS();
7615 if (elem->IsPoly()) {
7616 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7620 int aShapeId = FindShape( elem );
7622 SMDS_MeshElement* newElem =
7623 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7624 myLastCreatedElems.Append(newElem);
7625 if (aShapeId && newElem)
7626 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7628 aMesh->RemoveElement(elem);
7633 //=======================================================================
7635 * \brief Convert elements contained in a submesh to quadratic
7636 * \retval int - nb of checked elements
7638 //=======================================================================
7640 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
7641 SMESH_MesherHelper& theHelper,
7642 const bool theForce3d)
7645 if( !theSm ) return nbElem;
7647 const bool notFromGroups = false;
7648 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7649 while(ElemItr->more())
7652 const SMDS_MeshElement* elem = ElemItr->next();
7653 if( !elem || elem->IsQuadratic() ) continue;
7655 int id = elem->GetID();
7656 int nbNodes = elem->NbNodes();
7657 vector<const SMDS_MeshNode *> aNds (nbNodes);
7659 for(int i = 0; i < nbNodes; i++)
7661 aNds[i] = elem->GetNode(i);
7663 SMDSAbs_ElementType aType = elem->GetType();
7665 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7667 const SMDS_MeshElement* NewElem = 0;
7673 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7681 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7684 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7691 case SMDSAbs_Volume :
7696 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7699 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
7702 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7705 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7706 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7716 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7718 theSm->AddElement( NewElem );
7723 //=======================================================================
7724 //function : ConvertToQuadratic
7726 //=======================================================================
7727 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7729 SMESHDS_Mesh* meshDS = GetMeshDS();
7731 SMESH_MesherHelper aHelper(*myMesh);
7732 aHelper.SetIsQuadratic( true );
7733 const bool notFromGroups = false;
7735 int nbCheckedElems = 0;
7736 if ( myMesh->HasShapeToMesh() )
7738 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7740 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7741 while ( smIt->more() ) {
7742 SMESH_subMesh* sm = smIt->next();
7743 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7744 aHelper.SetSubShape( sm->GetSubShape() );
7745 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7750 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7751 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7753 SMESHDS_SubMesh *smDS = 0;
7754 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7755 while(aEdgeItr->more())
7757 const SMDS_MeshEdge* edge = aEdgeItr->next();
7758 if(edge && !edge->IsQuadratic())
7760 int id = edge->GetID();
7761 const SMDS_MeshNode* n1 = edge->GetNode(0);
7762 const SMDS_MeshNode* n2 = edge->GetNode(1);
7764 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7766 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7767 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7770 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7771 while(aFaceItr->more())
7773 const SMDS_MeshFace* face = aFaceItr->next();
7774 if(!face || face->IsQuadratic() ) continue;
7776 int id = face->GetID();
7777 int nbNodes = face->NbNodes();
7778 vector<const SMDS_MeshNode *> aNds (nbNodes);
7780 for(int i = 0; i < nbNodes; i++)
7782 aNds[i] = face->GetNode(i);
7785 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7787 SMDS_MeshFace * NewFace = 0;
7791 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7794 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7799 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7801 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7802 while(aVolumeItr->more())
7804 const SMDS_MeshVolume* volume = aVolumeItr->next();
7805 if(!volume || volume->IsQuadratic() ) continue;
7807 int id = volume->GetID();
7808 int nbNodes = volume->NbNodes();
7809 vector<const SMDS_MeshNode *> aNds (nbNodes);
7811 for(int i = 0; i < nbNodes; i++)
7813 aNds[i] = volume->GetNode(i);
7816 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7818 SMDS_MeshVolume * NewVolume = 0;
7822 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7823 aNds[3], id, theForce3d );
7826 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7827 aNds[3], aNds[4], id, theForce3d);
7830 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7831 aNds[3], aNds[4], aNds[5], id, theForce3d);
7834 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7835 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7840 ReplaceElemInGroups(volume, NewVolume, meshDS);
7843 if ( !theForce3d ) {
7844 aHelper.SetSubShape(0); // apply to the whole mesh
7845 aHelper.FixQuadraticElements();
7849 //=======================================================================
7851 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7852 * \retval int - nb of checked elements
7854 //=======================================================================
7856 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7857 SMDS_ElemIteratorPtr theItr,
7858 const int theShapeID)
7861 SMESHDS_Mesh* meshDS = GetMeshDS();
7862 const bool notFromGroups = false;
7864 while( theItr->more() )
7866 const SMDS_MeshElement* elem = theItr->next();
7868 if( elem && elem->IsQuadratic())
7870 int id = elem->GetID();
7871 int nbNodes = elem->NbNodes();
7872 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7873 aNds.reserve( nbNodes );
7874 mediumNodes.reserve( nbNodes );
7876 for(int i = 0; i < nbNodes; i++)
7878 const SMDS_MeshNode* n = elem->GetNode(i);
7880 if( elem->IsMediumNode( n ) )
7881 mediumNodes.push_back( n );
7883 aNds.push_back( n );
7885 if( aNds.empty() ) continue;
7886 SMDSAbs_ElementType aType = elem->GetType();
7888 //remove old quadratic element
7889 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7891 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7892 ReplaceElemInGroups(elem, NewElem, meshDS);
7893 if( theSm && NewElem )
7894 theSm->AddElement( NewElem );
7896 // remove medium nodes
7897 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7898 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7899 const SMDS_MeshNode* n = *nIt;
7900 if ( n->NbInverseElements() == 0 ) {
7901 if ( n->GetPosition()->GetShapeId() != theShapeID )
7902 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7903 ( n->GetPosition()->GetShapeId() ));
7905 meshDS->RemoveFreeNode( n, theSm );
7913 //=======================================================================
7914 //function : ConvertFromQuadratic
7916 //=======================================================================
7917 bool SMESH_MeshEditor::ConvertFromQuadratic()
7919 int nbCheckedElems = 0;
7920 if ( myMesh->HasShapeToMesh() )
7922 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7924 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7925 while ( smIt->more() ) {
7926 SMESH_subMesh* sm = smIt->next();
7927 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7928 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7934 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7935 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7937 SMESHDS_SubMesh *aSM = 0;
7938 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7944 //=======================================================================
7945 //function : SewSideElements
7947 //=======================================================================
7949 SMESH_MeshEditor::Sew_Error
7950 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7951 TIDSortedElemSet& theSide2,
7952 const SMDS_MeshNode* theFirstNode1,
7953 const SMDS_MeshNode* theFirstNode2,
7954 const SMDS_MeshNode* theSecondNode1,
7955 const SMDS_MeshNode* theSecondNode2)
7957 myLastCreatedElems.Clear();
7958 myLastCreatedNodes.Clear();
7960 MESSAGE ("::::SewSideElements()");
7961 if ( theSide1.size() != theSide2.size() )
7962 return SEW_DIFF_NB_OF_ELEMENTS;
7964 Sew_Error aResult = SEW_OK;
7966 // 1. Build set of faces representing each side
7967 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7968 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7970 // =======================================================================
7971 // 1. Build set of faces representing each side:
7972 // =======================================================================
7973 // a. build set of nodes belonging to faces
7974 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7975 // c. create temporary faces representing side of volumes if correspondent
7976 // face does not exist
7978 SMESHDS_Mesh* aMesh = GetMeshDS();
7979 SMDS_Mesh aTmpFacesMesh;
7980 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7981 set<const SMDS_MeshElement*> volSet1, volSet2;
7982 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7983 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7984 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7985 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7986 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7987 int iSide, iFace, iNode;
7989 for ( iSide = 0; iSide < 2; iSide++ ) {
7990 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7991 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7992 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7993 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7994 set<const SMDS_MeshElement*>::iterator vIt;
7995 TIDSortedElemSet::iterator eIt;
7996 set<const SMDS_MeshNode*>::iterator nIt;
7998 // check that given nodes belong to given elements
7999 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8000 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8001 int firstIndex = -1, secondIndex = -1;
8002 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8003 const SMDS_MeshElement* elem = *eIt;
8004 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
8005 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8006 if ( firstIndex > -1 && secondIndex > -1 ) break;
8008 if ( firstIndex < 0 || secondIndex < 0 ) {
8009 // we can simply return until temporary faces created
8010 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8013 // -----------------------------------------------------------
8014 // 1a. Collect nodes of existing faces
8015 // and build set of face nodes in order to detect missing
8016 // faces corresponing to sides of volumes
8017 // -----------------------------------------------------------
8019 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8021 // loop on the given element of a side
8022 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8023 //const SMDS_MeshElement* elem = *eIt;
8024 const SMDS_MeshElement* elem = *eIt;
8025 if ( elem->GetType() == SMDSAbs_Face ) {
8026 faceSet->insert( elem );
8027 set <const SMDS_MeshNode*> faceNodeSet;
8028 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8029 while ( nodeIt->more() ) {
8030 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8031 nodeSet->insert( n );
8032 faceNodeSet.insert( n );
8034 setOfFaceNodeSet.insert( faceNodeSet );
8036 else if ( elem->GetType() == SMDSAbs_Volume )
8037 volSet->insert( elem );
8039 // ------------------------------------------------------------------------------
8040 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8041 // ------------------------------------------------------------------------------
8043 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8044 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8045 while ( fIt->more() ) { // loop on faces sharing a node
8046 const SMDS_MeshElement* f = fIt->next();
8047 if ( faceSet->find( f ) == faceSet->end() ) {
8048 // check if all nodes are in nodeSet and
8049 // complete setOfFaceNodeSet if they are
8050 set <const SMDS_MeshNode*> faceNodeSet;
8051 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8052 bool allInSet = true;
8053 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8054 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8055 if ( nodeSet->find( n ) == nodeSet->end() )
8058 faceNodeSet.insert( n );
8061 faceSet->insert( f );
8062 setOfFaceNodeSet.insert( faceNodeSet );
8068 // -------------------------------------------------------------------------
8069 // 1c. Create temporary faces representing sides of volumes if correspondent
8070 // face does not exist
8071 // -------------------------------------------------------------------------
8073 if ( !volSet->empty() ) {
8074 //int nodeSetSize = nodeSet->size();
8076 // loop on given volumes
8077 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8078 SMDS_VolumeTool vol (*vIt);
8079 // loop on volume faces: find free faces
8080 // --------------------------------------
8081 list<const SMDS_MeshElement* > freeFaceList;
8082 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8083 if ( !vol.IsFreeFace( iFace ))
8085 // check if there is already a face with same nodes in a face set
8086 const SMDS_MeshElement* aFreeFace = 0;
8087 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8088 int nbNodes = vol.NbFaceNodes( iFace );
8089 set <const SMDS_MeshNode*> faceNodeSet;
8090 vol.GetFaceNodes( iFace, faceNodeSet );
8091 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8093 // no such a face is given but it still can exist, check it
8094 if ( nbNodes == 3 ) {
8095 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8097 else if ( nbNodes == 4 ) {
8098 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8101 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8102 aFreeFace = aMesh->FindFace(poly_nodes);
8106 // create a temporary face
8107 if ( nbNodes == 3 ) {
8108 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8110 else if ( nbNodes == 4 ) {
8111 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8114 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8115 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8119 freeFaceList.push_back( aFreeFace );
8121 } // loop on faces of a volume
8123 // choose one of several free faces
8124 // --------------------------------------
8125 if ( freeFaceList.size() > 1 ) {
8126 // choose a face having max nb of nodes shared by other elems of a side
8127 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8128 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8129 while ( fIt != freeFaceList.end() ) { // loop on free faces
8130 int nbSharedNodes = 0;
8131 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8132 while ( nodeIt->more() ) { // loop on free face nodes
8133 const SMDS_MeshNode* n =
8134 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8135 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8136 while ( invElemIt->more() ) {
8137 const SMDS_MeshElement* e = invElemIt->next();
8138 if ( faceSet->find( e ) != faceSet->end() )
8140 if ( elemSet->find( e ) != elemSet->end() )
8144 if ( nbSharedNodes >= maxNbNodes ) {
8145 maxNbNodes = nbSharedNodes;
8149 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8151 if ( freeFaceList.size() > 1 )
8153 // could not choose one face, use another way
8154 // choose a face most close to the bary center of the opposite side
8155 gp_XYZ aBC( 0., 0., 0. );
8156 set <const SMDS_MeshNode*> addedNodes;
8157 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8158 eIt = elemSet2->begin();
8159 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8160 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8161 while ( nodeIt->more() ) { // loop on free face nodes
8162 const SMDS_MeshNode* n =
8163 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8164 if ( addedNodes.insert( n ).second )
8165 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8168 aBC /= addedNodes.size();
8169 double minDist = DBL_MAX;
8170 fIt = freeFaceList.begin();
8171 while ( fIt != freeFaceList.end() ) { // loop on free faces
8173 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8174 while ( nodeIt->more() ) { // loop on free face nodes
8175 const SMDS_MeshNode* n =
8176 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8177 gp_XYZ p( n->X(),n->Y(),n->Z() );
8178 dist += ( aBC - p ).SquareModulus();
8180 if ( dist < minDist ) {
8182 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8185 fIt = freeFaceList.erase( fIt++ );
8188 } // choose one of several free faces of a volume
8190 if ( freeFaceList.size() == 1 ) {
8191 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8192 faceSet->insert( aFreeFace );
8193 // complete a node set with nodes of a found free face
8194 // for ( iNode = 0; iNode < ; iNode++ )
8195 // nodeSet->insert( fNodes[ iNode ] );
8198 } // loop on volumes of a side
8200 // // complete a set of faces if new nodes in a nodeSet appeared
8201 // // ----------------------------------------------------------
8202 // if ( nodeSetSize != nodeSet->size() ) {
8203 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8204 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8205 // while ( fIt->more() ) { // loop on faces sharing a node
8206 // const SMDS_MeshElement* f = fIt->next();
8207 // if ( faceSet->find( f ) == faceSet->end() ) {
8208 // // check if all nodes are in nodeSet and
8209 // // complete setOfFaceNodeSet if they are
8210 // set <const SMDS_MeshNode*> faceNodeSet;
8211 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8212 // bool allInSet = true;
8213 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8214 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8215 // if ( nodeSet->find( n ) == nodeSet->end() )
8216 // allInSet = false;
8218 // faceNodeSet.insert( n );
8220 // if ( allInSet ) {
8221 // faceSet->insert( f );
8222 // setOfFaceNodeSet.insert( faceNodeSet );
8228 } // Create temporary faces, if there are volumes given
8231 if ( faceSet1.size() != faceSet2.size() ) {
8232 // delete temporary faces: they are in reverseElements of actual nodes
8233 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8234 while ( tmpFaceIt->more() )
8235 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8236 MESSAGE("Diff nb of faces");
8237 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8240 // ============================================================
8241 // 2. Find nodes to merge:
8242 // bind a node to remove to a node to put instead
8243 // ============================================================
8245 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
8246 if ( theFirstNode1 != theFirstNode2 )
8247 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
8248 if ( theSecondNode1 != theSecondNode2 )
8249 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
8251 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8252 set< long > linkIdSet; // links to process
8253 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
8255 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
8256 list< NLink > linkList[2];
8257 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8258 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8259 // loop on links in linkList; find faces by links and append links
8260 // of the found faces to linkList
8261 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8262 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8263 NLink link[] = { *linkIt[0], *linkIt[1] };
8264 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
8265 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
8268 // by links, find faces in the face sets,
8269 // and find indices of link nodes in the found faces;
8270 // in a face set, there is only one or no face sharing a link
8271 // ---------------------------------------------------------------
8273 const SMDS_MeshElement* face[] = { 0, 0 };
8274 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
8275 vector<const SMDS_MeshNode*> fnodes1(9);
8276 vector<const SMDS_MeshNode*> fnodes2(9);
8277 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
8278 vector<const SMDS_MeshNode*> notLinkNodes1(6);
8279 vector<const SMDS_MeshNode*> notLinkNodes2(6);
8280 int iLinkNode[2][2];
8281 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8282 const SMDS_MeshNode* n1 = link[iSide].first;
8283 const SMDS_MeshNode* n2 = link[iSide].second;
8284 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8285 set< const SMDS_MeshElement* > fMap;
8286 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
8287 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
8288 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8289 while ( fIt->more() ) { // loop on faces sharing a node
8290 const SMDS_MeshElement* f = fIt->next();
8291 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8292 ! fMap.insert( f ).second ) // f encounters twice
8294 if ( face[ iSide ] ) {
8295 MESSAGE( "2 faces per link " );
8296 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
8300 faceSet->erase( f );
8301 // get face nodes and find ones of a link
8306 fnodes1.resize(f->NbNodes()+1);
8307 notLinkNodes1.resize(f->NbNodes()-2);
8310 fnodes2.resize(f->NbNodes()+1);
8311 notLinkNodes2.resize(f->NbNodes()-2);
8314 if(!f->IsQuadratic()) {
8315 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
8316 while ( nIt->more() ) {
8317 const SMDS_MeshNode* n =
8318 static_cast<const SMDS_MeshNode*>( nIt->next() );
8320 iLinkNode[ iSide ][ 0 ] = iNode;
8322 else if ( n == n2 ) {
8323 iLinkNode[ iSide ][ 1 ] = iNode;
8325 //else if ( notLinkNodes[ iSide ][ 0 ] )
8326 // notLinkNodes[ iSide ][ 1 ] = n;
8328 // notLinkNodes[ iSide ][ 0 ] = n;
8332 notLinkNodes1[nbl] = n;
8333 //notLinkNodes1.push_back(n);
8335 notLinkNodes2[nbl] = n;
8336 //notLinkNodes2.push_back(n);
8338 //faceNodes[ iSide ][ iNode++ ] = n;
8340 fnodes1[iNode++] = n;
8343 fnodes2[iNode++] = n;
8347 else { // f->IsQuadratic()
8348 const SMDS_QuadraticFaceOfNodes* F =
8349 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
8350 // use special nodes iterator
8351 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8352 while ( anIter->more() ) {
8353 const SMDS_MeshNode* n =
8354 static_cast<const SMDS_MeshNode*>( anIter->next() );
8356 iLinkNode[ iSide ][ 0 ] = iNode;
8358 else if ( n == n2 ) {
8359 iLinkNode[ iSide ][ 1 ] = iNode;
8364 notLinkNodes1[nbl] = n;
8367 notLinkNodes2[nbl] = n;
8371 fnodes1[iNode++] = n;
8374 fnodes2[iNode++] = n;
8378 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
8380 fnodes1[iNode] = fnodes1[0];
8383 fnodes2[iNode] = fnodes1[0];
8390 // check similarity of elements of the sides
8391 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8392 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8393 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8394 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8397 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8399 break; // do not return because it s necessary to remove tmp faces
8402 // set nodes to merge
8403 // -------------------
8405 if ( face[0] && face[1] ) {
8406 int nbNodes = face[0]->NbNodes();
8407 if ( nbNodes != face[1]->NbNodes() ) {
8408 MESSAGE("Diff nb of face nodes");
8409 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8410 break; // do not return because it s necessary to remove tmp faces
8412 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
8413 if ( nbNodes == 3 ) {
8414 //nReplaceMap.insert( TNodeNodeMap::value_type
8415 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8416 nReplaceMap.insert( TNodeNodeMap::value_type
8417 ( notLinkNodes1[0], notLinkNodes2[0] ));
8420 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8421 // analyse link orientation in faces
8422 int i1 = iLinkNode[ iSide ][ 0 ];
8423 int i2 = iLinkNode[ iSide ][ 1 ];
8424 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
8425 // if notLinkNodes are the first and the last ones, then
8426 // their order does not correspond to the link orientation
8427 if (( i1 == 1 && i2 == 2 ) ||
8428 ( i1 == 2 && i2 == 1 ))
8429 reverse[ iSide ] = !reverse[ iSide ];
8431 if ( reverse[0] == reverse[1] ) {
8432 //nReplaceMap.insert( TNodeNodeMap::value_type
8433 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8434 //nReplaceMap.insert( TNodeNodeMap::value_type
8435 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
8436 for(int nn=0; nn<nbNodes-2; nn++) {
8437 nReplaceMap.insert( TNodeNodeMap::value_type
8438 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
8442 //nReplaceMap.insert( TNodeNodeMap::value_type
8443 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
8444 //nReplaceMap.insert( TNodeNodeMap::value_type
8445 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
8446 for(int nn=0; nn<nbNodes-2; nn++) {
8447 nReplaceMap.insert( TNodeNodeMap::value_type
8448 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
8453 // add other links of the faces to linkList
8454 // -----------------------------------------
8456 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
8457 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8458 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
8459 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
8460 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
8461 if ( !iter_isnew.second ) { // already in a set: no need to process
8462 linkIdSet.erase( iter_isnew.first );
8464 else // new in set == encountered for the first time: add
8466 //const SMDS_MeshNode* n1 = nodes[ iNode ];
8467 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
8468 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
8469 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
8470 linkList[0].push_back ( NLink( n1, n2 ));
8471 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8475 } // loop on link lists
8477 if ( aResult == SEW_OK &&
8478 ( linkIt[0] != linkList[0].end() ||
8479 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
8480 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
8481 " " << (faceSetPtr[1]->empty()));
8482 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8485 // ====================================================================
8486 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8487 // ====================================================================
8489 // delete temporary faces: they are in reverseElements of actual nodes
8490 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8491 while ( tmpFaceIt->more() )
8492 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8494 if ( aResult != SEW_OK)
8497 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
8498 // loop on nodes replacement map
8499 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
8500 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
8501 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
8502 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
8503 nodeIDsToRemove.push_back( nToRemove->GetID() );
8504 // loop on elements sharing nToRemove
8505 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
8506 while ( invElemIt->more() ) {
8507 const SMDS_MeshElement* e = invElemIt->next();
8508 // get a new suite of nodes: make replacement
8509 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
8510 vector< const SMDS_MeshNode*> nodes( nbNodes );
8511 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8512 while ( nIt->more() ) {
8513 const SMDS_MeshNode* n =
8514 static_cast<const SMDS_MeshNode*>( nIt->next() );
8515 nnIt = nReplaceMap.find( n );
8516 if ( nnIt != nReplaceMap.end() ) {
8522 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8523 // elemIDsToRemove.push_back( e->GetID() );
8526 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8530 Remove( nodeIDsToRemove, true );
8535 //================================================================================
8537 * \brief Find corresponding nodes in two sets of faces
8538 * \param theSide1 - first face set
8539 * \param theSide2 - second first face
8540 * \param theFirstNode1 - a boundary node of set 1
8541 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8542 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8543 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8544 * \param nReplaceMap - output map of corresponding nodes
8545 * \retval bool - is a success or not
8547 //================================================================================
8550 //#define DEBUG_MATCHING_NODES
8553 SMESH_MeshEditor::Sew_Error
8554 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8555 set<const SMDS_MeshElement*>& theSide2,
8556 const SMDS_MeshNode* theFirstNode1,
8557 const SMDS_MeshNode* theFirstNode2,
8558 const SMDS_MeshNode* theSecondNode1,
8559 const SMDS_MeshNode* theSecondNode2,
8560 TNodeNodeMap & nReplaceMap)
8562 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8564 nReplaceMap.clear();
8565 if ( theFirstNode1 != theFirstNode2 )
8566 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8567 if ( theSecondNode1 != theSecondNode2 )
8568 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8570 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8571 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8573 list< NLink > linkList[2];
8574 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8575 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8577 // loop on links in linkList; find faces by links and append links
8578 // of the found faces to linkList
8579 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8580 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8581 NLink link[] = { *linkIt[0], *linkIt[1] };
8582 if ( linkSet.find( link[0] ) == linkSet.end() )
8585 // by links, find faces in the face sets,
8586 // and find indices of link nodes in the found faces;
8587 // in a face set, there is only one or no face sharing a link
8588 // ---------------------------------------------------------------
8590 const SMDS_MeshElement* face[] = { 0, 0 };
8591 list<const SMDS_MeshNode*> notLinkNodes[2];
8592 //bool reverse[] = { false, false }; // order of notLinkNodes
8594 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8596 const SMDS_MeshNode* n1 = link[iSide].first;
8597 const SMDS_MeshNode* n2 = link[iSide].second;
8598 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8599 set< const SMDS_MeshElement* > facesOfNode1;
8600 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8602 // during a loop of the first node, we find all faces around n1,
8603 // during a loop of the second node, we find one face sharing both n1 and n2
8604 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8605 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8606 while ( fIt->more() ) { // loop on faces sharing a node
8607 const SMDS_MeshElement* f = fIt->next();
8608 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8609 ! facesOfNode1.insert( f ).second ) // f encounters twice
8611 if ( face[ iSide ] ) {
8612 MESSAGE( "2 faces per link " );
8613 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8616 faceSet->erase( f );
8618 // get not link nodes
8619 int nbN = f->NbNodes();
8620 if ( f->IsQuadratic() )
8622 nbNodes[ iSide ] = nbN;
8623 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8624 int i1 = f->GetNodeIndex( n1 );
8625 int i2 = f->GetNodeIndex( n2 );
8626 int iEnd = nbN, iBeg = -1, iDelta = 1;
8627 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8629 std::swap( iEnd, iBeg ); iDelta = -1;
8634 if ( i == iEnd ) i = iBeg + iDelta;
8635 if ( i == i1 ) break;
8636 nodes.push_back ( f->GetNode( i ) );
8642 // check similarity of elements of the sides
8643 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8644 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8645 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8646 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8649 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8653 // set nodes to merge
8654 // -------------------
8656 if ( face[0] && face[1] ) {
8657 if ( nbNodes[0] != nbNodes[1] ) {
8658 MESSAGE("Diff nb of face nodes");
8659 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8661 #ifdef DEBUG_MATCHING_NODES
8662 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8663 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8664 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8666 int nbN = nbNodes[0];
8668 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8669 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8670 for ( int i = 0 ; i < nbN - 2; ++i ) {
8671 #ifdef DEBUG_MATCHING_NODES
8672 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8674 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8678 // add other links of the face 1 to linkList
8679 // -----------------------------------------
8681 const SMDS_MeshElement* f0 = face[0];
8682 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8683 for ( int i = 0; i < nbN; i++ )
8685 const SMDS_MeshNode* n2 = f0->GetNode( i );
8686 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8687 linkSet.insert( SMESH_TLink( n1, n2 ));
8688 if ( !iter_isnew.second ) { // already in a set: no need to process
8689 linkSet.erase( iter_isnew.first );
8691 else // new in set == encountered for the first time: add
8693 #ifdef DEBUG_MATCHING_NODES
8694 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8695 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8697 linkList[0].push_back ( NLink( n1, n2 ));
8698 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8703 } // loop on link lists
8709 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8710 \param theElems - the list of elements (edges or faces) to be replicated
8711 The nodes for duplication could be found from these elements
8712 \param theNodesNot - list of nodes to NOT replicate
8713 \param theAffectedElems - the list of elements (cells and edges) to which the
8714 replicated nodes should be associated to.
8715 \return TRUE if operation has been completed successfully, FALSE otherwise
8717 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
8718 const TIDSortedElemSet& theNodesNot,
8719 const TIDSortedElemSet& theAffectedElems )
8721 myLastCreatedElems.Clear();
8722 myLastCreatedNodes.Clear();
8724 if ( theElems.size() == 0 )
8727 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8732 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8733 // duplicate elements and nodes
8734 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
8735 // replce nodes by duplications
8736 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
8741 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8742 \param theMeshDS - mesh instance
8743 \param theElems - the elements replicated or modified (nodes should be changed)
8744 \param theNodesNot - nodes to NOT replicate
8745 \param theNodeNodeMap - relation of old node to new created node
8746 \param theIsDoubleElem - flag os to replicate element or modify
8747 \return TRUE if operation has been completed successfully, FALSE otherwise
8749 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
8750 const TIDSortedElemSet& theElems,
8751 const TIDSortedElemSet& theNodesNot,
8752 std::map< const SMDS_MeshNode*,
8753 const SMDS_MeshNode* >& theNodeNodeMap,
8754 const bool theIsDoubleElem )
8756 // iterate on through element and duplicate them (by nodes duplication)
8758 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8759 for ( ; elemItr != theElems.end(); ++elemItr )
8761 const SMDS_MeshElement* anElem = *elemItr;
8765 bool isDuplicate = false;
8766 // duplicate nodes to duplicate element
8767 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
8768 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8770 while ( anIter->more() )
8773 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8774 SMDS_MeshNode* aNewNode = aCurrNode;
8775 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
8776 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
8777 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
8780 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
8781 theNodeNodeMap[ aCurrNode ] = aNewNode;
8782 myLastCreatedNodes.Append( aNewNode );
8784 isDuplicate |= (aCurrNode != aNewNode);
8785 newNodes[ ind++ ] = aNewNode;
8790 if ( theIsDoubleElem )
8791 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
8793 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
8801 \brief Check if element located inside shape
8802 \return TRUE if IN or ON shape, FALSE otherwise
8805 static bool isInside(const SMDS_MeshElement* theElem,
8806 BRepClass3d_SolidClassifier& theBsc3d,
8807 const double theTol)
8809 gp_XYZ centerXYZ (0, 0, 0);
8810 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
8811 while (aNodeItr->more())
8813 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
8814 centerXYZ += gp_XYZ(aNode->X(), aNode->Y(), aNode->Z());
8816 gp_Pnt aPnt(centerXYZ);
8817 theBsc3d.Perform(aPnt, theTol);
8818 TopAbs_State aState = theBsc3d.State();
8819 return (aState == TopAbs_IN || aState == TopAbs_ON );
8823 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8824 \param theNodes - identifiers of nodes to be doubled
8825 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
8826 nodes. If list of element identifiers is empty then nodes are doubled but
8827 they not assigned to elements
8828 \return TRUE if operation has been completed successfully, FALSE otherwise
8830 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
8831 const std::list< int >& theListOfModifiedElems )
8833 myLastCreatedElems.Clear();
8834 myLastCreatedNodes.Clear();
8836 if ( theListOfNodes.size() == 0 )
8839 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8843 // iterate through nodes and duplicate them
8845 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8847 std::list< int >::const_iterator aNodeIter;
8848 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
8850 int aCurr = *aNodeIter;
8851 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
8857 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
8860 anOldNodeToNewNode[ aNode ] = aNewNode;
8861 myLastCreatedNodes.Append( aNewNode );
8865 // Create map of new nodes for modified elements
8867 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
8869 std::list< int >::const_iterator anElemIter;
8870 for ( anElemIter = theListOfModifiedElems.begin();
8871 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
8873 int aCurr = *anElemIter;
8874 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
8878 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
8880 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8882 while ( anIter->more() )
8884 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8885 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
8887 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
8888 aNodeArr[ ind++ ] = aNewNode;
8891 aNodeArr[ ind++ ] = aCurrNode;
8893 anElemToNodes[ anElem ] = aNodeArr;
8896 // Change nodes of elements
8898 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
8899 anElemToNodesIter = anElemToNodes.begin();
8900 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
8902 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
8903 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
8905 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
8912 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8913 \param theElems - group of of elements (edges or faces) to be replicated
8914 \param theNodesNot - group of nodes not to replicated
8915 \param theShape - shape to detect affected elements (element which geometric center
8916 located on or inside shape).
8917 The replicated nodes should be associated to affected elements.
8918 \return TRUE if operation has been completed successfully, FALSE otherwise
8921 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
8922 const TIDSortedElemSet& theNodesNot,
8923 const TopoDS_Shape& theShape )
8925 if ( theShape.IsNull() )
8928 const double aTol = Precision::Confusion();
8929 BRepClass3d_SolidClassifier bsc3d(theShape);
8930 bsc3d.PerformInfinitePoint(aTol);
8932 // iterates on indicated elements and get elements by back references from their nodes
8933 TIDSortedElemSet anAffected;
8934 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8935 for ( ; elemItr != theElems.end(); ++elemItr )
8937 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
8941 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
8942 while ( nodeItr->more() )
8944 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
8945 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
8947 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
8948 while ( backElemItr->more() )
8950 SMDS_MeshElement* curElem = (SMDS_MeshElement*)backElemItr->next();
8951 if ( curElem && theElems.find(curElem) == theElems.end() &&
8952 isInside( curElem, bsc3d, aTol ) )
8953 anAffected.insert( curElem );
8957 return DoubleNodes( theElems, theNodesNot, anAffected );
8961 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
8962 * The created 2D mesh elements based on nodes of free faces of boundary volumes
8963 * \return TRUE if operation has been completed successfully, FALSE otherwise
8966 bool SMESH_MeshEditor::Make2DMeshFrom3D()
8968 // iterates on volume elements and detect all free faces on them
8969 SMESHDS_Mesh* aMesh = GetMeshDS();
8973 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
8976 const SMDS_MeshVolume* volume = vIt->next();
8977 SMDS_VolumeTool vTool( volume );
8978 vTool.SetExternalNormal();
8979 const bool isPoly = volume->IsPoly();
8980 const bool isQuad = volume->IsQuadratic();
8981 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
8983 if (!vTool.IsFreeFace(iface))
8985 vector<const SMDS_MeshNode *> nodes;
8986 int nbFaceNodes = vTool.NbFaceNodes(iface);
8987 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
8989 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
8990 nodes.push_back(faceNodes[inode]);
8992 for ( inode = 1; inode < nbFaceNodes; inode += 2)
8993 nodes.push_back(faceNodes[inode]);
8995 // add new face based on volume nodes
8996 if (aMesh->FindFace( nodes ) )
8997 continue; // face already exsist
8998 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );