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);
2810 itNN[ iNode ] = listNewNodes.begin();
2811 prevNod[ iNode ] = node;
2812 nextNod[ iNode ] = listNewNodes.front();
2813 if( !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 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
5588 gc = accumulate( xyz.begin(), xyz.end(), gc );
5589 gc /= element->NbNodes();
5591 // compute face normal using gc
5592 gp_Vec normal(0,0,0);
5593 xyz.push_back( xyz.front() );
5594 for ( int i = 0; i < element->NbNodes(); ++i )
5596 gp_Vec edge( xyz[i], xyz[i+1]);
5597 gp_Vec n2gc( xyz[i], gc );
5598 normal += edge ^ n2gc;
5600 double faceDoubleArea = normal.Magnitude();
5601 if ( faceDoubleArea <= numeric_limits<double>::min() )
5602 return true; // invalid face
5603 normal /= faceDoubleArea;
5605 // check if the point lays on face plane
5606 gp_Vec n2p( xyz[0], point );
5607 if ( fabs( n2p * normal ) > tol )
5608 return true; // not on face plane
5610 // check if point is out of face boundary
5612 for ( i = 0; !out && i < element->NbNodes(); ++i )
5614 gp_Vec edge( xyz[i], xyz[i+1]);
5615 gp_Vec n2p ( xyz[i], point );
5616 gp_Vec cross = edge ^ n2p;
5617 out = ( cross * normal < -tol );
5619 if ( out && element->IsPoly() )
5621 // define point position by the closest edge
5622 double minDist = numeric_limits<double>::max();
5624 for ( i = 0; i < element->NbNodes(); ++i )
5626 gp_Vec edge( xyz[i], xyz[i+1]);
5627 gp_Vec n1p ( xyz[i], point);
5628 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
5629 if ( dist < minDist )
5632 gp_Vec edge( xyz[iMinDist], xyz[iMinDist+1]);
5633 gp_Vec n2p ( xyz[iMinDist], point );
5634 gp_Vec cross = edge ^ n2p;
5635 out = ( cross * normal < -tol );
5639 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
5641 for ( int i = 1; i < element->NbNodes(); ++i )
5643 gp_Vec edge( xyz[i-1], xyz[i]);
5644 gp_Vec n1p ( xyz[i-1], point);
5645 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
5648 gp_Vec n2p( xyz[i], point );
5649 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
5654 // Node or 0D element -------------------------------------------------------------------------
5656 gp_Vec n2p ( xyz[0], point );
5657 return n2p.Magnitude() <= tol;
5662 //=======================================================================
5663 //function : SimplifyFace
5665 //=======================================================================
5666 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5667 vector<const SMDS_MeshNode *>& poly_nodes,
5668 vector<int>& quantities) const
5670 int nbNodes = faceNodes.size();
5675 set<const SMDS_MeshNode*> nodeSet;
5677 // get simple seq of nodes
5678 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5679 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5680 int iSimple = 0, nbUnique = 0;
5682 simpleNodes[iSimple++] = faceNodes[0];
5684 for (int iCur = 1; iCur < nbNodes; iCur++) {
5685 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5686 simpleNodes[iSimple++] = faceNodes[iCur];
5687 if (nodeSet.insert( faceNodes[iCur] ).second)
5691 int nbSimple = iSimple;
5692 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5702 bool foundLoop = (nbSimple > nbUnique);
5705 set<const SMDS_MeshNode*> loopSet;
5706 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5707 const SMDS_MeshNode* n = simpleNodes[iSimple];
5708 if (!loopSet.insert( n ).second) {
5712 int iC = 0, curLast = iSimple;
5713 for (; iC < curLast; iC++) {
5714 if (simpleNodes[iC] == n) break;
5716 int loopLen = curLast - iC;
5718 // create sub-element
5720 quantities.push_back(loopLen);
5721 for (; iC < curLast; iC++) {
5722 poly_nodes.push_back(simpleNodes[iC]);
5725 // shift the rest nodes (place from the first loop position)
5726 for (iC = curLast + 1; iC < nbSimple; iC++) {
5727 simpleNodes[iC - loopLen] = simpleNodes[iC];
5729 nbSimple -= loopLen;
5732 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5733 } // while (foundLoop)
5737 quantities.push_back(iSimple);
5738 for (int i = 0; i < iSimple; i++)
5739 poly_nodes.push_back(simpleNodes[i]);
5745 //=======================================================================
5746 //function : MergeNodes
5747 //purpose : In each group, the cdr of nodes are substituted by the first one
5749 //=======================================================================
5751 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5753 myLastCreatedElems.Clear();
5754 myLastCreatedNodes.Clear();
5756 SMESHDS_Mesh* aMesh = GetMeshDS();
5758 TNodeNodeMap nodeNodeMap; // node to replace - new node
5759 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5760 list< int > rmElemIds, rmNodeIds;
5762 // Fill nodeNodeMap and elems
5764 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5765 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5766 list<const SMDS_MeshNode*>& nodes = *grIt;
5767 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5768 const SMDS_MeshNode* nToKeep = *nIt;
5769 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5770 const SMDS_MeshNode* nToRemove = *nIt;
5771 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5772 if ( nToRemove != nToKeep ) {
5773 rmNodeIds.push_back( nToRemove->GetID() );
5774 AddToSameGroups( nToKeep, nToRemove, aMesh );
5777 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5778 while ( invElemIt->more() ) {
5779 const SMDS_MeshElement* elem = invElemIt->next();
5784 // Change element nodes or remove an element
5786 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5787 for ( ; eIt != elems.end(); eIt++ ) {
5788 const SMDS_MeshElement* elem = *eIt;
5789 int nbNodes = elem->NbNodes();
5790 int aShapeId = FindShape( elem );
5792 set<const SMDS_MeshNode*> nodeSet;
5793 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5794 int iUnique = 0, iCur = 0, nbRepl = 0;
5795 vector<int> iRepl( nbNodes );
5797 // get new seq of nodes
5798 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5799 while ( itN->more() ) {
5800 const SMDS_MeshNode* n =
5801 static_cast<const SMDS_MeshNode*>( itN->next() );
5803 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5804 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5806 // BUG 0020185: begin
5808 bool stopRecur = false;
5809 set<const SMDS_MeshNode*> nodesRecur;
5810 nodesRecur.insert(n);
5811 while (!stopRecur) {
5812 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5813 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5814 n = (*nnIt_i).second;
5815 if (!nodesRecur.insert(n).second) {
5816 // error: recursive dependancy
5825 iRepl[ nbRepl++ ] = iCur;
5827 curNodes[ iCur ] = n;
5828 bool isUnique = nodeSet.insert( n ).second;
5830 uniqueNodes[ iUnique++ ] = n;
5834 // Analyse element topology after replacement
5837 int nbUniqueNodes = nodeSet.size();
5838 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5839 // Polygons and Polyhedral volumes
5840 if (elem->IsPoly()) {
5842 if (elem->GetType() == SMDSAbs_Face) {
5844 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5846 for (; inode < nbNodes; inode++) {
5847 face_nodes[inode] = curNodes[inode];
5850 vector<const SMDS_MeshNode *> polygons_nodes;
5851 vector<int> quantities;
5852 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5856 for (int iface = 0; iface < nbNew - 1; iface++) {
5857 int nbNodes = quantities[iface];
5858 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5859 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5860 poly_nodes[ii] = polygons_nodes[inode];
5862 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5863 myLastCreatedElems.Append(newElem);
5865 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5867 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5870 rmElemIds.push_back(elem->GetID());
5874 else if (elem->GetType() == SMDSAbs_Volume) {
5875 // Polyhedral volume
5876 if (nbUniqueNodes < 4) {
5877 rmElemIds.push_back(elem->GetID());
5880 // each face has to be analized in order to check volume validity
5881 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5882 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5884 int nbFaces = aPolyedre->NbFaces();
5886 vector<const SMDS_MeshNode *> poly_nodes;
5887 vector<int> quantities;
5889 for (int iface = 1; iface <= nbFaces; iface++) {
5890 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5891 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5893 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5894 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5895 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5896 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5897 faceNode = (*nnIt).second;
5899 faceNodes[inode - 1] = faceNode;
5902 SimplifyFace(faceNodes, poly_nodes, quantities);
5905 if (quantities.size() > 3) {
5906 // to be done: remove coincident faces
5909 if (quantities.size() > 3)
5910 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5912 rmElemIds.push_back(elem->GetID());
5916 rmElemIds.push_back(elem->GetID());
5927 switch ( nbNodes ) {
5928 case 2: ///////////////////////////////////// EDGE
5929 isOk = false; break;
5930 case 3: ///////////////////////////////////// TRIANGLE
5931 isOk = false; break;
5933 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5935 else { //////////////////////////////////// QUADRANGLE
5936 if ( nbUniqueNodes < 3 )
5938 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5939 isOk = false; // opposite nodes stick
5942 case 6: ///////////////////////////////////// PENTAHEDRON
5943 if ( nbUniqueNodes == 4 ) {
5944 // ---------------------------------> tetrahedron
5946 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5947 // all top nodes stick: reverse a bottom
5948 uniqueNodes[ 0 ] = curNodes [ 1 ];
5949 uniqueNodes[ 1 ] = curNodes [ 0 ];
5951 else if (nbRepl == 3 &&
5952 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5953 // all bottom nodes stick: set a top before
5954 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5955 uniqueNodes[ 0 ] = curNodes [ 3 ];
5956 uniqueNodes[ 1 ] = curNodes [ 4 ];
5957 uniqueNodes[ 2 ] = curNodes [ 5 ];
5959 else if (nbRepl == 4 &&
5960 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5961 // a lateral face turns into a line: reverse a bottom
5962 uniqueNodes[ 0 ] = curNodes [ 1 ];
5963 uniqueNodes[ 1 ] = curNodes [ 0 ];
5968 else if ( nbUniqueNodes == 5 ) {
5969 // PENTAHEDRON --------------------> 2 tetrahedrons
5970 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
5971 // a bottom node sticks with a linked top one
5973 SMDS_MeshElement* newElem =
5974 aMesh->AddVolume(curNodes[ 3 ],
5977 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
5978 myLastCreatedElems.Append(newElem);
5980 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5981 // 2. : reverse a bottom
5982 uniqueNodes[ 0 ] = curNodes [ 1 ];
5983 uniqueNodes[ 1 ] = curNodes [ 0 ];
5993 if(elem->IsQuadratic()) { // Quadratic quadrangle
6006 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6007 uniqueNodes[0] = curNodes[0];
6008 uniqueNodes[1] = curNodes[2];
6009 uniqueNodes[2] = curNodes[3];
6010 uniqueNodes[3] = curNodes[5];
6011 uniqueNodes[4] = curNodes[6];
6012 uniqueNodes[5] = curNodes[7];
6015 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6016 uniqueNodes[0] = curNodes[0];
6017 uniqueNodes[1] = curNodes[1];
6018 uniqueNodes[2] = curNodes[2];
6019 uniqueNodes[3] = curNodes[4];
6020 uniqueNodes[4] = curNodes[5];
6021 uniqueNodes[5] = curNodes[6];
6024 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6025 uniqueNodes[0] = curNodes[1];
6026 uniqueNodes[1] = curNodes[2];
6027 uniqueNodes[2] = curNodes[3];
6028 uniqueNodes[3] = curNodes[5];
6029 uniqueNodes[4] = curNodes[6];
6030 uniqueNodes[5] = curNodes[0];
6033 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6034 uniqueNodes[0] = curNodes[0];
6035 uniqueNodes[1] = curNodes[1];
6036 uniqueNodes[2] = curNodes[3];
6037 uniqueNodes[3] = curNodes[4];
6038 uniqueNodes[4] = curNodes[6];
6039 uniqueNodes[5] = curNodes[7];
6042 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6043 uniqueNodes[0] = curNodes[0];
6044 uniqueNodes[1] = curNodes[2];
6045 uniqueNodes[2] = curNodes[3];
6046 uniqueNodes[3] = curNodes[1];
6047 uniqueNodes[4] = curNodes[6];
6048 uniqueNodes[5] = curNodes[7];
6051 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6052 uniqueNodes[0] = curNodes[0];
6053 uniqueNodes[1] = curNodes[1];
6054 uniqueNodes[2] = curNodes[2];
6055 uniqueNodes[3] = curNodes[4];
6056 uniqueNodes[4] = curNodes[5];
6057 uniqueNodes[5] = curNodes[7];
6060 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6061 uniqueNodes[0] = curNodes[0];
6062 uniqueNodes[1] = curNodes[1];
6063 uniqueNodes[2] = curNodes[3];
6064 uniqueNodes[3] = curNodes[4];
6065 uniqueNodes[4] = curNodes[2];
6066 uniqueNodes[5] = curNodes[7];
6069 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6070 uniqueNodes[0] = curNodes[0];
6071 uniqueNodes[1] = curNodes[1];
6072 uniqueNodes[2] = curNodes[2];
6073 uniqueNodes[3] = curNodes[4];
6074 uniqueNodes[4] = curNodes[5];
6075 uniqueNodes[5] = curNodes[3];
6081 //////////////////////////////////// HEXAHEDRON
6083 SMDS_VolumeTool hexa (elem);
6084 hexa.SetExternalNormal();
6085 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6086 //////////////////////// ---> tetrahedron
6087 for ( int iFace = 0; iFace < 6; iFace++ ) {
6088 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6089 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6090 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6091 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6092 // one face turns into a point ...
6093 int iOppFace = hexa.GetOppFaceIndex( iFace );
6094 ind = hexa.GetFaceNodesIndices( iOppFace );
6096 iUnique = 2; // reverse a tetrahedron bottom
6097 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6098 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6100 else if ( iUnique >= 0 )
6101 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6103 if ( nbStick == 1 ) {
6104 // ... and the opposite one - into a triangle.
6106 ind = hexa.GetFaceNodesIndices( iFace );
6107 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6114 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6115 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6116 for ( int iFace = 0; iFace < 6; iFace++ ) {
6117 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6118 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6119 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6120 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6121 // one face turns into a point ...
6122 int iOppFace = hexa.GetOppFaceIndex( iFace );
6123 ind = hexa.GetFaceNodesIndices( iOppFace );
6125 iUnique = 2; // reverse a tetrahedron 1 bottom
6126 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6127 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6129 else if ( iUnique >= 0 )
6130 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6132 if ( nbStick == 0 ) {
6133 // ... and the opposite one is a quadrangle
6135 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6136 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6139 SMDS_MeshElement* newElem =
6140 aMesh->AddVolume(curNodes[ind[ 0 ]],
6143 curNodes[indTop[ 0 ]]);
6144 myLastCreatedElems.Append(newElem);
6146 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6153 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6154 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6155 // find indices of quad and tri faces
6156 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6157 for ( iFace = 0; iFace < 6; iFace++ ) {
6158 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6160 for ( iCur = 0; iCur < 4; iCur++ )
6161 nodeSet.insert( curNodes[ind[ iCur ]] );
6162 nbUniqueNodes = nodeSet.size();
6163 if ( nbUniqueNodes == 3 )
6164 iTriFace[ nbTri++ ] = iFace;
6165 else if ( nbUniqueNodes == 4 )
6166 iQuadFace[ nbQuad++ ] = iFace;
6168 if (nbQuad == 2 && nbTri == 4 &&
6169 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6170 // 2 opposite quadrangles stuck with a diagonal;
6171 // sample groups of merged indices: (0-4)(2-6)
6172 // --------------------------------------------> 2 tetrahedrons
6173 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6174 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6175 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6176 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6177 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6178 // stuck with 0-2 diagonal
6186 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6187 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6188 // stuck with 1-3 diagonal
6200 uniqueNodes[ 0 ] = curNodes [ i0 ];
6201 uniqueNodes[ 1 ] = curNodes [ i1d ];
6202 uniqueNodes[ 2 ] = curNodes [ i3d ];
6203 uniqueNodes[ 3 ] = curNodes [ i0t ];
6206 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6210 myLastCreatedElems.Append(newElem);
6212 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6215 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6216 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6217 // --------------------------------------------> prism
6218 // find 2 opposite triangles
6220 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6221 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6222 // find indices of kept and replaced nodes
6223 // and fill unique nodes of 2 opposite triangles
6224 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6225 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6226 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6227 // fill unique nodes
6230 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6231 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
6232 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6234 // iCur of a linked node of the opposite face (make normals co-directed):
6235 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6236 // check that correspondent corners of triangles are linked
6237 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6240 uniqueNodes[ iUnique ] = n;
6241 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6250 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6256 } // switch ( nbNodes )
6258 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6261 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
6262 // Change nodes of polyedre
6263 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6264 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6266 int nbFaces = aPolyedre->NbFaces();
6268 vector<const SMDS_MeshNode *> poly_nodes;
6269 vector<int> quantities (nbFaces);
6271 for (int iface = 1; iface <= nbFaces; iface++) {
6272 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6273 quantities[iface - 1] = nbFaceNodes;
6275 for (inode = 1; inode <= nbFaceNodes; inode++) {
6276 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6278 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6279 if (nnIt != nodeNodeMap.end()) { // curNode sticks
6280 curNode = (*nnIt).second;
6282 poly_nodes.push_back(curNode);
6285 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6289 // Change regular element or polygon
6290 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
6294 // Remove invalid regular element or invalid polygon
6295 rmElemIds.push_back( elem->GetID() );
6298 } // loop on elements
6300 // Remove equal nodes and bad elements
6302 Remove( rmNodeIds, true );
6303 Remove( rmElemIds, false );
6308 // ========================================================
6309 // class : SortableElement
6310 // purpose : allow sorting elements basing on their nodes
6311 // ========================================================
6312 class SortableElement : public set <const SMDS_MeshElement*>
6316 SortableElement( const SMDS_MeshElement* theElem )
6319 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6320 while ( nodeIt->more() )
6321 this->insert( nodeIt->next() );
6324 const SMDS_MeshElement* Get() const
6327 void Set(const SMDS_MeshElement* e) const
6332 mutable const SMDS_MeshElement* myElem;
6335 //=======================================================================
6336 //function : FindEqualElements
6337 //purpose : Return list of group of elements built on the same nodes.
6338 // Search among theElements or in the whole mesh if theElements is empty
6339 //=======================================================================
6340 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
6341 TListOfListOfElementsID & theGroupsOfElementsID)
6343 myLastCreatedElems.Clear();
6344 myLastCreatedNodes.Clear();
6346 typedef set<const SMDS_MeshElement*> TElemsSet;
6347 typedef map< SortableElement, int > TMapOfNodeSet;
6348 typedef list<int> TGroupOfElems;
6351 if ( theElements.empty() )
6352 { // get all elements in the mesh
6353 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
6354 while ( eIt->more() )
6355 elems.insert( elems.end(), eIt->next());
6358 elems = theElements;
6360 vector< TGroupOfElems > arrayOfGroups;
6361 TGroupOfElems groupOfElems;
6362 TMapOfNodeSet mapOfNodeSet;
6364 TElemsSet::iterator elemIt = elems.begin();
6365 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
6366 const SMDS_MeshElement* curElem = *elemIt;
6367 SortableElement SE(curElem);
6370 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
6371 if( !(pp.second) ) {
6372 TMapOfNodeSet::iterator& itSE = pp.first;
6373 ind = (*itSE).second;
6374 arrayOfGroups[ind].push_back(curElem->GetID());
6377 groupOfElems.clear();
6378 groupOfElems.push_back(curElem->GetID());
6379 arrayOfGroups.push_back(groupOfElems);
6384 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
6385 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
6386 groupOfElems = *groupIt;
6387 if ( groupOfElems.size() > 1 ) {
6388 groupOfElems.sort();
6389 theGroupsOfElementsID.push_back(groupOfElems);
6394 //=======================================================================
6395 //function : MergeElements
6396 //purpose : In each given group, substitute all elements by the first one.
6397 //=======================================================================
6399 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
6401 myLastCreatedElems.Clear();
6402 myLastCreatedNodes.Clear();
6404 typedef list<int> TListOfIDs;
6405 TListOfIDs rmElemIds; // IDs of elems to remove
6407 SMESHDS_Mesh* aMesh = GetMeshDS();
6409 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
6410 while ( groupsIt != theGroupsOfElementsID.end() ) {
6411 TListOfIDs& aGroupOfElemID = *groupsIt;
6412 aGroupOfElemID.sort();
6413 int elemIDToKeep = aGroupOfElemID.front();
6414 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
6415 aGroupOfElemID.pop_front();
6416 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
6417 while ( idIt != aGroupOfElemID.end() ) {
6418 int elemIDToRemove = *idIt;
6419 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
6420 // add the kept element in groups of removed one (PAL15188)
6421 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
6422 rmElemIds.push_back( elemIDToRemove );
6428 Remove( rmElemIds, false );
6431 //=======================================================================
6432 //function : MergeEqualElements
6433 //purpose : Remove all but one of elements built on the same nodes.
6434 //=======================================================================
6436 void SMESH_MeshEditor::MergeEqualElements()
6438 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
6439 to merge equal elements in the whole mesh */
6440 TListOfListOfElementsID aGroupsOfElementsID;
6441 FindEqualElements(aMeshElements, aGroupsOfElementsID);
6442 MergeElements(aGroupsOfElementsID);
6445 //=======================================================================
6446 //function : FindFaceInSet
6447 //purpose : Return a face having linked nodes n1 and n2 and which is
6448 // - not in avoidSet,
6449 // - in elemSet provided that !elemSet.empty()
6450 //=======================================================================
6452 const SMDS_MeshElement*
6453 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
6454 const SMDS_MeshNode* n2,
6455 const TIDSortedElemSet& elemSet,
6456 const TIDSortedElemSet& avoidSet)
6459 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
6460 while ( invElemIt->more() ) { // loop on inverse elements of n1
6461 const SMDS_MeshElement* elem = invElemIt->next();
6462 if (avoidSet.find( elem ) != avoidSet.end() )
6464 if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
6466 // get face nodes and find index of n1
6467 int i1, nbN = elem->NbNodes(), iNode = 0;
6468 //const SMDS_MeshNode* faceNodes[ nbN ], *n;
6469 vector<const SMDS_MeshNode*> faceNodes( nbN );
6470 const SMDS_MeshNode* n;
6471 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6472 while ( nIt->more() ) {
6473 faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6474 if ( faceNodes[ iNode++ ] == n1 )
6477 // find a n2 linked to n1
6478 if(!elem->IsQuadratic()) {
6479 for ( iNode = 0; iNode < 2; iNode++ ) {
6480 if ( iNode ) // node before n1
6481 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6482 else // node after n1
6483 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6488 else { // analysis for quadratic elements
6489 bool IsFind = false;
6490 // check using only corner nodes
6491 for ( iNode = 0; iNode < 2; iNode++ ) {
6492 if ( iNode ) // node before n1
6493 n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
6494 else // node after n1
6495 n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
6503 // check using all nodes
6504 const SMDS_QuadraticFaceOfNodes* F =
6505 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6506 // use special nodes iterator
6508 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6509 while ( anIter->more() ) {
6510 faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
6511 if ( faceNodes[ iNode++ ] == n1 )
6514 for ( iNode = 0; iNode < 2; iNode++ ) {
6515 if ( iNode ) // node before n1
6516 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6517 else // node after n1
6518 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6524 } // end analysis for quadratic elements
6529 //=======================================================================
6530 //function : findAdjacentFace
6532 //=======================================================================
6534 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6535 const SMDS_MeshNode* n2,
6536 const SMDS_MeshElement* elem)
6538 TIDSortedElemSet elemSet, avoidSet;
6540 avoidSet.insert ( elem );
6541 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6544 //=======================================================================
6545 //function : FindFreeBorder
6547 //=======================================================================
6549 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6551 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
6552 const SMDS_MeshNode* theSecondNode,
6553 const SMDS_MeshNode* theLastNode,
6554 list< const SMDS_MeshNode* > & theNodes,
6555 list< const SMDS_MeshElement* >& theFaces)
6557 if ( !theFirstNode || !theSecondNode )
6559 // find border face between theFirstNode and theSecondNode
6560 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6564 theFaces.push_back( curElem );
6565 theNodes.push_back( theFirstNode );
6566 theNodes.push_back( theSecondNode );
6568 //vector<const SMDS_MeshNode*> nodes;
6569 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6570 TIDSortedElemSet foundElems;
6571 bool needTheLast = ( theLastNode != 0 );
6573 while ( nStart != theLastNode ) {
6574 if ( nStart == theFirstNode )
6575 return !needTheLast;
6577 // find all free border faces sharing form nStart
6579 list< const SMDS_MeshElement* > curElemList;
6580 list< const SMDS_MeshNode* > nStartList;
6581 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6582 while ( invElemIt->more() ) {
6583 const SMDS_MeshElement* e = invElemIt->next();
6584 if ( e == curElem || foundElems.insert( e ).second ) {
6586 int iNode = 0, nbNodes = e->NbNodes();
6587 //const SMDS_MeshNode* nodes[nbNodes+1];
6588 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6590 if(e->IsQuadratic()) {
6591 const SMDS_QuadraticFaceOfNodes* F =
6592 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6593 // use special nodes iterator
6594 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6595 while( anIter->more() ) {
6596 nodes[ iNode++ ] = anIter->next();
6600 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6601 while ( nIt->more() )
6602 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6604 nodes[ iNode ] = nodes[ 0 ];
6606 for ( iNode = 0; iNode < nbNodes; iNode++ )
6607 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6608 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6609 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6611 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6612 curElemList.push_back( e );
6616 // analyse the found
6618 int nbNewBorders = curElemList.size();
6619 if ( nbNewBorders == 0 ) {
6620 // no free border furthermore
6621 return !needTheLast;
6623 else if ( nbNewBorders == 1 ) {
6624 // one more element found
6626 nStart = nStartList.front();
6627 curElem = curElemList.front();
6628 theFaces.push_back( curElem );
6629 theNodes.push_back( nStart );
6632 // several continuations found
6633 list< const SMDS_MeshElement* >::iterator curElemIt;
6634 list< const SMDS_MeshNode* >::iterator nStartIt;
6635 // check if one of them reached the last node
6636 if ( needTheLast ) {
6637 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6638 curElemIt!= curElemList.end();
6639 curElemIt++, nStartIt++ )
6640 if ( *nStartIt == theLastNode ) {
6641 theFaces.push_back( *curElemIt );
6642 theNodes.push_back( *nStartIt );
6646 // find the best free border by the continuations
6647 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6648 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6649 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6650 curElemIt!= curElemList.end();
6651 curElemIt++, nStartIt++ )
6653 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6654 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6655 // find one more free border
6656 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6660 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6661 // choice: clear a worse one
6662 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6663 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6664 contNodes[ iWorse ].clear();
6665 contFaces[ iWorse ].clear();
6668 if ( contNodes[0].empty() && contNodes[1].empty() )
6671 // append the best free border
6672 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6673 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6674 theNodes.pop_back(); // remove nIgnore
6675 theNodes.pop_back(); // remove nStart
6676 theFaces.pop_back(); // remove curElem
6677 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6678 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6679 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6680 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6683 } // several continuations found
6684 } // while ( nStart != theLastNode )
6689 //=======================================================================
6690 //function : CheckFreeBorderNodes
6691 //purpose : Return true if the tree nodes are on a free border
6692 //=======================================================================
6694 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6695 const SMDS_MeshNode* theNode2,
6696 const SMDS_MeshNode* theNode3)
6698 list< const SMDS_MeshNode* > nodes;
6699 list< const SMDS_MeshElement* > faces;
6700 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6703 //=======================================================================
6704 //function : SewFreeBorder
6706 //=======================================================================
6708 SMESH_MeshEditor::Sew_Error
6709 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6710 const SMDS_MeshNode* theBordSecondNode,
6711 const SMDS_MeshNode* theBordLastNode,
6712 const SMDS_MeshNode* theSideFirstNode,
6713 const SMDS_MeshNode* theSideSecondNode,
6714 const SMDS_MeshNode* theSideThirdNode,
6715 const bool theSideIsFreeBorder,
6716 const bool toCreatePolygons,
6717 const bool toCreatePolyedrs)
6719 myLastCreatedElems.Clear();
6720 myLastCreatedNodes.Clear();
6722 MESSAGE("::SewFreeBorder()");
6723 Sew_Error aResult = SEW_OK;
6725 // ====================================
6726 // find side nodes and elements
6727 // ====================================
6729 list< const SMDS_MeshNode* > nSide[ 2 ];
6730 list< const SMDS_MeshElement* > eSide[ 2 ];
6731 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6732 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6736 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6737 nSide[0], eSide[0])) {
6738 MESSAGE(" Free Border 1 not found " );
6739 aResult = SEW_BORDER1_NOT_FOUND;
6741 if (theSideIsFreeBorder) {
6744 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6745 nSide[1], eSide[1])) {
6746 MESSAGE(" Free Border 2 not found " );
6747 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6750 if ( aResult != SEW_OK )
6753 if (!theSideIsFreeBorder) {
6757 // -------------------------------------------------------------------------
6759 // 1. If nodes to merge are not coincident, move nodes of the free border
6760 // from the coord sys defined by the direction from the first to last
6761 // nodes of the border to the correspondent sys of the side 2
6762 // 2. On the side 2, find the links most co-directed with the correspondent
6763 // links of the free border
6764 // -------------------------------------------------------------------------
6766 // 1. Since sewing may brake if there are volumes to split on the side 2,
6767 // we wont move nodes but just compute new coordinates for them
6768 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6769 TNodeXYZMap nBordXYZ;
6770 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6771 list< const SMDS_MeshNode* >::iterator nBordIt;
6773 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6774 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6775 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6776 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6777 double tol2 = 1.e-8;
6778 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6779 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6780 // Need node movement.
6782 // find X and Z axes to create trsf
6783 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6785 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6787 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6790 gp_Ax3 toBordAx( Pb1, Zb, X );
6791 gp_Ax3 fromSideAx( Ps1, Zs, X );
6792 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6794 gp_Trsf toBordSys, fromSide2Sys;
6795 toBordSys.SetTransformation( toBordAx );
6796 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6797 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6800 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6801 const SMDS_MeshNode* n = *nBordIt;
6802 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6803 toBordSys.Transforms( xyz );
6804 fromSide2Sys.Transforms( xyz );
6805 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6809 // just insert nodes XYZ in the nBordXYZ map
6810 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6811 const SMDS_MeshNode* n = *nBordIt;
6812 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6816 // 2. On the side 2, find the links most co-directed with the correspondent
6817 // links of the free border
6819 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6820 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6821 sideNodes.push_back( theSideFirstNode );
6823 bool hasVolumes = false;
6824 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6825 set<long> foundSideLinkIDs, checkedLinkIDs;
6826 SMDS_VolumeTool volume;
6827 //const SMDS_MeshNode* faceNodes[ 4 ];
6829 const SMDS_MeshNode* sideNode;
6830 const SMDS_MeshElement* sideElem;
6831 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6832 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6833 nBordIt = bordNodes.begin();
6835 // border node position and border link direction to compare with
6836 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6837 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6838 // choose next side node by link direction or by closeness to
6839 // the current border node:
6840 bool searchByDir = ( *nBordIt != theBordLastNode );
6842 // find the next node on the Side 2
6844 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6846 checkedLinkIDs.clear();
6847 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6849 // loop on inverse elements of current node (prevSideNode) on the Side 2
6850 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6851 while ( invElemIt->more() )
6853 const SMDS_MeshElement* elem = invElemIt->next();
6854 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6855 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6856 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6857 bool isVolume = volume.Set( elem );
6858 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6859 if ( isVolume ) // --volume
6861 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6862 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6863 if(elem->IsQuadratic()) {
6864 const SMDS_QuadraticFaceOfNodes* F =
6865 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6866 // use special nodes iterator
6867 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6868 while( anIter->more() ) {
6869 nodes[ iNode ] = anIter->next();
6870 if ( nodes[ iNode++ ] == prevSideNode )
6871 iPrevNode = iNode - 1;
6875 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6876 while ( nIt->more() ) {
6877 nodes[ iNode ] = cast2Node( nIt->next() );
6878 if ( nodes[ iNode++ ] == prevSideNode )
6879 iPrevNode = iNode - 1;
6882 // there are 2 links to check
6887 // loop on links, to be precise, on the second node of links
6888 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6889 const SMDS_MeshNode* n = nodes[ iNode ];
6891 if ( !volume.IsLinked( n, prevSideNode ))
6895 if ( iNode ) // a node before prevSideNode
6896 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6897 else // a node after prevSideNode
6898 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6900 // check if this link was already used
6901 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6902 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6903 if (!isJustChecked &&
6904 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6906 // test a link geometrically
6907 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6908 bool linkIsBetter = false;
6909 double dot = 0.0, dist = 0.0;
6910 if ( searchByDir ) { // choose most co-directed link
6911 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6912 linkIsBetter = ( dot > maxDot );
6914 else { // choose link with the node closest to bordPos
6915 dist = ( nextXYZ - bordPos ).SquareModulus();
6916 linkIsBetter = ( dist < minDist );
6918 if ( linkIsBetter ) {
6927 } // loop on inverse elements of prevSideNode
6930 MESSAGE(" Cant find path by links of the Side 2 ");
6931 return SEW_BAD_SIDE_NODES;
6933 sideNodes.push_back( sideNode );
6934 sideElems.push_back( sideElem );
6935 foundSideLinkIDs.insert ( linkID );
6936 prevSideNode = sideNode;
6938 if ( *nBordIt == theBordLastNode )
6939 searchByDir = false;
6941 // find the next border link to compare with
6942 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6943 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6944 // move to next border node if sideNode is before forward border node (bordPos)
6945 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6946 prevBordNode = *nBordIt;
6948 bordPos = nBordXYZ[ *nBordIt ];
6949 bordDir = bordPos - nBordXYZ[ prevBordNode ];
6950 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6954 while ( sideNode != theSideSecondNode );
6956 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6957 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6958 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6960 } // end nodes search on the side 2
6962 // ============================
6963 // sew the border to the side 2
6964 // ============================
6966 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
6967 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6969 TListOfListOfNodes nodeGroupsToMerge;
6970 if ( nbNodes[0] == nbNodes[1] ||
6971 ( theSideIsFreeBorder && !theSideThirdNode)) {
6973 // all nodes are to be merged
6975 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6976 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6977 nIt[0]++, nIt[1]++ )
6979 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6980 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6981 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6986 // insert new nodes into the border and the side to get equal nb of segments
6988 // get normalized parameters of nodes on the borders
6989 //double param[ 2 ][ maxNbNodes ];
6991 param[0] = new double [ maxNbNodes ];
6992 param[1] = new double [ maxNbNodes ];
6994 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6995 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
6996 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
6997 const SMDS_MeshNode* nPrev = *nIt;
6998 double bordLength = 0;
6999 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7000 const SMDS_MeshNode* nCur = *nIt;
7001 gp_XYZ segment (nCur->X() - nPrev->X(),
7002 nCur->Y() - nPrev->Y(),
7003 nCur->Z() - nPrev->Z());
7004 double segmentLen = segment.Modulus();
7005 bordLength += segmentLen;
7006 param[ iBord ][ iNode ] = bordLength;
7009 // normalize within [0,1]
7010 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7011 param[ iBord ][ iNode ] /= bordLength;
7015 // loop on border segments
7016 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7017 int i[ 2 ] = { 0, 0 };
7018 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7019 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7021 TElemOfNodeListMap insertMap;
7022 TElemOfNodeListMap::iterator insertMapIt;
7024 // key: elem to insert nodes into
7025 // value: 2 nodes to insert between + nodes to be inserted
7027 bool next[ 2 ] = { false, false };
7029 // find min adjacent segment length after sewing
7030 double nextParam = 10., prevParam = 0;
7031 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7032 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7033 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7034 if ( i[ iBord ] > 0 )
7035 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7037 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7038 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7039 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7041 // choose to insert or to merge nodes
7042 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7043 if ( Abs( du ) <= minSegLen * 0.2 ) {
7046 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7047 const SMDS_MeshNode* n0 = *nIt[0];
7048 const SMDS_MeshNode* n1 = *nIt[1];
7049 nodeGroupsToMerge.back().push_back( n1 );
7050 nodeGroupsToMerge.back().push_back( n0 );
7051 // position of node of the border changes due to merge
7052 param[ 0 ][ i[0] ] += du;
7053 // move n1 for the sake of elem shape evaluation during insertion.
7054 // n1 will be removed by MergeNodes() anyway
7055 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7056 next[0] = next[1] = true;
7061 int intoBord = ( du < 0 ) ? 0 : 1;
7062 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7063 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7064 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7065 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7066 if ( intoBord == 1 ) {
7067 // move node of the border to be on a link of elem of the side
7068 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7069 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7070 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7071 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7072 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7074 insertMapIt = insertMap.find( elem );
7075 bool notFound = ( insertMapIt == insertMap.end() );
7076 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7078 // insert into another link of the same element:
7079 // 1. perform insertion into the other link of the elem
7080 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7081 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7082 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7083 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7084 // 2. perform insertion into the link of adjacent faces
7086 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7088 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7092 if (toCreatePolyedrs) {
7093 // perform insertion into the links of adjacent volumes
7094 UpdateVolumes(n12, n22, nodeList);
7096 // 3. find an element appeared on n1 and n2 after the insertion
7097 insertMap.erase( elem );
7098 elem = findAdjacentFace( n1, n2, 0 );
7100 if ( notFound || otherLink ) {
7101 // add element and nodes of the side into the insertMap
7102 insertMapIt = insertMap.insert
7103 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7104 (*insertMapIt).second.push_back( n1 );
7105 (*insertMapIt).second.push_back( n2 );
7107 // add node to be inserted into elem
7108 (*insertMapIt).second.push_back( nIns );
7109 next[ 1 - intoBord ] = true;
7112 // go to the next segment
7113 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7114 if ( next[ iBord ] ) {
7115 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7117 nPrev[ iBord ] = *nIt[ iBord ];
7118 nIt[ iBord ]++; i[ iBord ]++;
7122 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7124 // perform insertion of nodes into elements
7126 for (insertMapIt = insertMap.begin();
7127 insertMapIt != insertMap.end();
7130 const SMDS_MeshElement* elem = (*insertMapIt).first;
7131 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7132 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7133 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7135 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7137 if ( !theSideIsFreeBorder ) {
7138 // look for and insert nodes into the faces adjacent to elem
7140 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7142 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7147 if (toCreatePolyedrs) {
7148 // perform insertion into the links of adjacent volumes
7149 UpdateVolumes(n1, n2, nodeList);
7155 } // end: insert new nodes
7157 MergeNodes ( nodeGroupsToMerge );
7162 //=======================================================================
7163 //function : InsertNodesIntoLink
7164 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7165 // and theBetweenNode2 and split theElement
7166 //=======================================================================
7168 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7169 const SMDS_MeshNode* theBetweenNode1,
7170 const SMDS_MeshNode* theBetweenNode2,
7171 list<const SMDS_MeshNode*>& theNodesToInsert,
7172 const bool toCreatePoly)
7174 if ( theFace->GetType() != SMDSAbs_Face ) return;
7176 // find indices of 2 link nodes and of the rest nodes
7177 int iNode = 0, il1, il2, i3, i4;
7178 il1 = il2 = i3 = i4 = -1;
7179 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7180 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7182 if(theFace->IsQuadratic()) {
7183 const SMDS_QuadraticFaceOfNodes* F =
7184 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7185 // use special nodes iterator
7186 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7187 while( anIter->more() ) {
7188 const SMDS_MeshNode* n = anIter->next();
7189 if ( n == theBetweenNode1 )
7191 else if ( n == theBetweenNode2 )
7197 nodes[ iNode++ ] = n;
7201 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7202 while ( nodeIt->more() ) {
7203 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7204 if ( n == theBetweenNode1 )
7206 else if ( n == theBetweenNode2 )
7212 nodes[ iNode++ ] = n;
7215 if ( il1 < 0 || il2 < 0 || i3 < 0 )
7218 // arrange link nodes to go one after another regarding the face orientation
7219 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7220 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7225 aNodesToInsert.reverse();
7227 // check that not link nodes of a quadrangles are in good order
7228 int nbFaceNodes = theFace->NbNodes();
7229 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7235 if (toCreatePoly || theFace->IsPoly()) {
7238 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7240 // add nodes of face up to first node of link
7243 if(theFace->IsQuadratic()) {
7244 const SMDS_QuadraticFaceOfNodes* F =
7245 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7246 // use special nodes iterator
7247 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7248 while( anIter->more() && !isFLN ) {
7249 const SMDS_MeshNode* n = anIter->next();
7250 poly_nodes[iNode++] = n;
7251 if (n == nodes[il1]) {
7255 // add nodes to insert
7256 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7257 for (; nIt != aNodesToInsert.end(); nIt++) {
7258 poly_nodes[iNode++] = *nIt;
7260 // add nodes of face starting from last node of link
7261 while ( anIter->more() ) {
7262 poly_nodes[iNode++] = anIter->next();
7266 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7267 while ( nodeIt->more() && !isFLN ) {
7268 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7269 poly_nodes[iNode++] = n;
7270 if (n == nodes[il1]) {
7274 // add nodes to insert
7275 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7276 for (; nIt != aNodesToInsert.end(); nIt++) {
7277 poly_nodes[iNode++] = *nIt;
7279 // add nodes of face starting from last node of link
7280 while ( nodeIt->more() ) {
7281 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7282 poly_nodes[iNode++] = n;
7286 // edit or replace the face
7287 SMESHDS_Mesh *aMesh = GetMeshDS();
7289 if (theFace->IsPoly()) {
7290 aMesh->ChangePolygonNodes(theFace, poly_nodes);
7293 int aShapeId = FindShape( theFace );
7295 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7296 myLastCreatedElems.Append(newElem);
7297 if ( aShapeId && newElem )
7298 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7300 aMesh->RemoveElement(theFace);
7305 if( !theFace->IsQuadratic() ) {
7307 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7308 int nbLinkNodes = 2 + aNodesToInsert.size();
7309 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7310 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7311 linkNodes[ 0 ] = nodes[ il1 ];
7312 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7313 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7314 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7315 linkNodes[ iNode++ ] = *nIt;
7317 // decide how to split a quadrangle: compare possible variants
7318 // and choose which of splits to be a quadrangle
7319 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7320 if ( nbFaceNodes == 3 ) {
7321 iBestQuad = nbSplits;
7324 else if ( nbFaceNodes == 4 ) {
7325 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7326 double aBestRate = DBL_MAX;
7327 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7329 double aBadRate = 0;
7330 // evaluate elements quality
7331 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7332 if ( iSplit == iQuad ) {
7333 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7337 aBadRate += getBadRate( &quad, aCrit );
7340 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7342 nodes[ iSplit < iQuad ? i4 : i3 ]);
7343 aBadRate += getBadRate( &tria, aCrit );
7347 if ( aBadRate < aBestRate ) {
7349 aBestRate = aBadRate;
7354 // create new elements
7355 SMESHDS_Mesh *aMesh = GetMeshDS();
7356 int aShapeId = FindShape( theFace );
7359 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7360 SMDS_MeshElement* newElem = 0;
7361 if ( iSplit == iBestQuad )
7362 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7367 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7369 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7370 myLastCreatedElems.Append(newElem);
7371 if ( aShapeId && newElem )
7372 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7375 // change nodes of theFace
7376 const SMDS_MeshNode* newNodes[ 4 ];
7377 newNodes[ 0 ] = linkNodes[ i1 ];
7378 newNodes[ 1 ] = linkNodes[ i2 ];
7379 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7380 newNodes[ 3 ] = nodes[ i4 ];
7381 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7382 } // end if(!theFace->IsQuadratic())
7383 else { // theFace is quadratic
7384 // we have to split theFace on simple triangles and one simple quadrangle
7386 int nbshift = tmp*2;
7387 // shift nodes in nodes[] by nbshift
7389 for(i=0; i<nbshift; i++) {
7390 const SMDS_MeshNode* n = nodes[0];
7391 for(j=0; j<nbFaceNodes-1; j++) {
7392 nodes[j] = nodes[j+1];
7394 nodes[nbFaceNodes-1] = n;
7396 il1 = il1 - nbshift;
7397 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7398 // n0 n1 n2 n0 n1 n2
7399 // +-----+-----+ +-----+-----+
7408 // create new elements
7409 SMESHDS_Mesh *aMesh = GetMeshDS();
7410 int aShapeId = FindShape( theFace );
7413 if(nbFaceNodes==6) { // quadratic triangle
7414 SMDS_MeshElement* newElem =
7415 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7416 myLastCreatedElems.Append(newElem);
7417 if ( aShapeId && newElem )
7418 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7419 if(theFace->IsMediumNode(nodes[il1])) {
7420 // create quadrangle
7421 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
7422 myLastCreatedElems.Append(newElem);
7423 if ( aShapeId && newElem )
7424 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7430 // create quadrangle
7431 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
7432 myLastCreatedElems.Append(newElem);
7433 if ( aShapeId && newElem )
7434 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7440 else { // nbFaceNodes==8 - quadratic quadrangle
7441 SMDS_MeshElement* newElem =
7442 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7443 myLastCreatedElems.Append(newElem);
7444 if ( aShapeId && newElem )
7445 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7446 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
7447 myLastCreatedElems.Append(newElem);
7448 if ( aShapeId && newElem )
7449 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7450 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
7451 myLastCreatedElems.Append(newElem);
7452 if ( aShapeId && newElem )
7453 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7454 if(theFace->IsMediumNode(nodes[il1])) {
7455 // create quadrangle
7456 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
7457 myLastCreatedElems.Append(newElem);
7458 if ( aShapeId && newElem )
7459 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7465 // create quadrangle
7466 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7467 myLastCreatedElems.Append(newElem);
7468 if ( aShapeId && newElem )
7469 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7475 // create needed triangles using n1,n2,n3 and inserted nodes
7476 int nbn = 2 + aNodesToInsert.size();
7477 //const SMDS_MeshNode* aNodes[nbn];
7478 vector<const SMDS_MeshNode*> aNodes(nbn);
7479 aNodes[0] = nodes[n1];
7480 aNodes[nbn-1] = nodes[n2];
7481 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7482 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7483 aNodes[iNode++] = *nIt;
7485 for(i=1; i<nbn; i++) {
7486 SMDS_MeshElement* newElem =
7487 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7488 myLastCreatedElems.Append(newElem);
7489 if ( aShapeId && newElem )
7490 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7492 // remove old quadratic face
7493 aMesh->RemoveElement(theFace);
7497 //=======================================================================
7498 //function : UpdateVolumes
7500 //=======================================================================
7501 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
7502 const SMDS_MeshNode* theBetweenNode2,
7503 list<const SMDS_MeshNode*>& theNodesToInsert)
7505 myLastCreatedElems.Clear();
7506 myLastCreatedNodes.Clear();
7508 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7509 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7510 const SMDS_MeshElement* elem = invElemIt->next();
7512 // check, if current volume has link theBetweenNode1 - theBetweenNode2
7513 SMDS_VolumeTool aVolume (elem);
7514 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7517 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7518 int iface, nbFaces = aVolume.NbFaces();
7519 vector<const SMDS_MeshNode *> poly_nodes;
7520 vector<int> quantities (nbFaces);
7522 for (iface = 0; iface < nbFaces; iface++) {
7523 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7524 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7525 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7527 for (int inode = 0; inode < nbFaceNodes; inode++) {
7528 poly_nodes.push_back(faceNodes[inode]);
7530 if (nbInserted == 0) {
7531 if (faceNodes[inode] == theBetweenNode1) {
7532 if (faceNodes[inode + 1] == theBetweenNode2) {
7533 nbInserted = theNodesToInsert.size();
7535 // add nodes to insert
7536 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7537 for (; nIt != theNodesToInsert.end(); nIt++) {
7538 poly_nodes.push_back(*nIt);
7542 else if (faceNodes[inode] == theBetweenNode2) {
7543 if (faceNodes[inode + 1] == theBetweenNode1) {
7544 nbInserted = theNodesToInsert.size();
7546 // add nodes to insert in reversed order
7547 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7549 for (; nIt != theNodesToInsert.begin(); nIt--) {
7550 poly_nodes.push_back(*nIt);
7552 poly_nodes.push_back(*nIt);
7559 quantities[iface] = nbFaceNodes + nbInserted;
7562 // Replace or update the volume
7563 SMESHDS_Mesh *aMesh = GetMeshDS();
7565 if (elem->IsPoly()) {
7566 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7570 int aShapeId = FindShape( elem );
7572 SMDS_MeshElement* newElem =
7573 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7574 myLastCreatedElems.Append(newElem);
7575 if (aShapeId && newElem)
7576 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7578 aMesh->RemoveElement(elem);
7583 //=======================================================================
7585 * \brief Convert elements contained in a submesh to quadratic
7586 * \retval int - nb of checked elements
7588 //=======================================================================
7590 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
7591 SMESH_MesherHelper& theHelper,
7592 const bool theForce3d)
7595 if( !theSm ) return nbElem;
7597 const bool notFromGroups = false;
7598 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7599 while(ElemItr->more())
7602 const SMDS_MeshElement* elem = ElemItr->next();
7603 if( !elem || elem->IsQuadratic() ) continue;
7605 int id = elem->GetID();
7606 int nbNodes = elem->NbNodes();
7607 vector<const SMDS_MeshNode *> aNds (nbNodes);
7609 for(int i = 0; i < nbNodes; i++)
7611 aNds[i] = elem->GetNode(i);
7613 SMDSAbs_ElementType aType = elem->GetType();
7615 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7617 const SMDS_MeshElement* NewElem = 0;
7623 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7631 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7634 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7641 case SMDSAbs_Volume :
7646 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7649 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7652 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7653 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7663 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7665 theSm->AddElement( NewElem );
7670 //=======================================================================
7671 //function : ConvertToQuadratic
7673 //=======================================================================
7674 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7676 SMESHDS_Mesh* meshDS = GetMeshDS();
7678 SMESH_MesherHelper aHelper(*myMesh);
7679 aHelper.SetIsQuadratic( true );
7680 const bool notFromGroups = false;
7682 int nbCheckedElems = 0;
7683 if ( myMesh->HasShapeToMesh() )
7685 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7687 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7688 while ( smIt->more() ) {
7689 SMESH_subMesh* sm = smIt->next();
7690 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7691 aHelper.SetSubShape( sm->GetSubShape() );
7692 if ( !theForce3d) aHelper.SetCheckNodePosition(true);
7693 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7698 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7699 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7701 SMESHDS_SubMesh *smDS = 0;
7702 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7703 while(aEdgeItr->more())
7705 const SMDS_MeshEdge* edge = aEdgeItr->next();
7706 if(edge && !edge->IsQuadratic())
7708 int id = edge->GetID();
7709 const SMDS_MeshNode* n1 = edge->GetNode(0);
7710 const SMDS_MeshNode* n2 = edge->GetNode(1);
7712 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7714 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7715 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7718 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7719 while(aFaceItr->more())
7721 const SMDS_MeshFace* face = aFaceItr->next();
7722 if(!face || face->IsQuadratic() ) continue;
7724 int id = face->GetID();
7725 int nbNodes = face->NbNodes();
7726 vector<const SMDS_MeshNode *> aNds (nbNodes);
7728 for(int i = 0; i < nbNodes; i++)
7730 aNds[i] = face->GetNode(i);
7733 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7735 SMDS_MeshFace * NewFace = 0;
7739 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7742 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7747 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7749 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7750 while(aVolumeItr->more())
7752 const SMDS_MeshVolume* volume = aVolumeItr->next();
7753 if(!volume || volume->IsQuadratic() ) continue;
7755 int id = volume->GetID();
7756 int nbNodes = volume->NbNodes();
7757 vector<const SMDS_MeshNode *> aNds (nbNodes);
7759 for(int i = 0; i < nbNodes; i++)
7761 aNds[i] = volume->GetNode(i);
7764 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7766 SMDS_MeshVolume * NewVolume = 0;
7770 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7771 aNds[3], id, theForce3d );
7774 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7775 aNds[3], aNds[4], aNds[5], id, theForce3d);
7778 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7779 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7784 ReplaceElemInGroups(volume, NewVolume, meshDS);
7787 if ( !theForce3d ) {
7788 aHelper.SetSubShape(0); // apply to the whole mesh
7789 aHelper.FixQuadraticElements();
7793 //=======================================================================
7795 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7796 * \retval int - nb of checked elements
7798 //=======================================================================
7800 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7801 SMDS_ElemIteratorPtr theItr,
7802 const int theShapeID)
7805 SMESHDS_Mesh* meshDS = GetMeshDS();
7806 const bool notFromGroups = false;
7808 while( theItr->more() )
7810 const SMDS_MeshElement* elem = theItr->next();
7812 if( elem && elem->IsQuadratic())
7814 int id = elem->GetID();
7815 int nbNodes = elem->NbNodes();
7816 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7817 aNds.reserve( nbNodes );
7818 mediumNodes.reserve( nbNodes );
7820 for(int i = 0; i < nbNodes; i++)
7822 const SMDS_MeshNode* n = elem->GetNode(i);
7824 if( elem->IsMediumNode( n ) )
7825 mediumNodes.push_back( n );
7827 aNds.push_back( n );
7829 if( aNds.empty() ) continue;
7830 SMDSAbs_ElementType aType = elem->GetType();
7832 //remove old quadratic element
7833 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7835 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7836 ReplaceElemInGroups(elem, NewElem, meshDS);
7837 if( theSm && NewElem )
7838 theSm->AddElement( NewElem );
7840 // remove medium nodes
7841 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7842 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7843 const SMDS_MeshNode* n = *nIt;
7844 if ( n->NbInverseElements() == 0 ) {
7845 if ( n->GetPosition()->GetShapeId() != theShapeID )
7846 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7847 ( n->GetPosition()->GetShapeId() ));
7849 meshDS->RemoveFreeNode( n, theSm );
7857 //=======================================================================
7858 //function : ConvertFromQuadratic
7860 //=======================================================================
7861 bool SMESH_MeshEditor::ConvertFromQuadratic()
7863 int nbCheckedElems = 0;
7864 if ( myMesh->HasShapeToMesh() )
7866 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7868 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7869 while ( smIt->more() ) {
7870 SMESH_subMesh* sm = smIt->next();
7871 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7872 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7878 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7879 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7881 SMESHDS_SubMesh *aSM = 0;
7882 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7888 //=======================================================================
7889 //function : SewSideElements
7891 //=======================================================================
7893 SMESH_MeshEditor::Sew_Error
7894 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7895 TIDSortedElemSet& theSide2,
7896 const SMDS_MeshNode* theFirstNode1,
7897 const SMDS_MeshNode* theFirstNode2,
7898 const SMDS_MeshNode* theSecondNode1,
7899 const SMDS_MeshNode* theSecondNode2)
7901 myLastCreatedElems.Clear();
7902 myLastCreatedNodes.Clear();
7904 MESSAGE ("::::SewSideElements()");
7905 if ( theSide1.size() != theSide2.size() )
7906 return SEW_DIFF_NB_OF_ELEMENTS;
7908 Sew_Error aResult = SEW_OK;
7910 // 1. Build set of faces representing each side
7911 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7912 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7914 // =======================================================================
7915 // 1. Build set of faces representing each side:
7916 // =======================================================================
7917 // a. build set of nodes belonging to faces
7918 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7919 // c. create temporary faces representing side of volumes if correspondent
7920 // face does not exist
7922 SMESHDS_Mesh* aMesh = GetMeshDS();
7923 SMDS_Mesh aTmpFacesMesh;
7924 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7925 set<const SMDS_MeshElement*> volSet1, volSet2;
7926 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7927 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7928 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7929 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7930 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7931 int iSide, iFace, iNode;
7933 for ( iSide = 0; iSide < 2; iSide++ ) {
7934 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7935 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7936 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7937 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7938 set<const SMDS_MeshElement*>::iterator vIt;
7939 TIDSortedElemSet::iterator eIt;
7940 set<const SMDS_MeshNode*>::iterator nIt;
7942 // check that given nodes belong to given elements
7943 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7944 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7945 int firstIndex = -1, secondIndex = -1;
7946 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7947 const SMDS_MeshElement* elem = *eIt;
7948 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
7949 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7950 if ( firstIndex > -1 && secondIndex > -1 ) break;
7952 if ( firstIndex < 0 || secondIndex < 0 ) {
7953 // we can simply return until temporary faces created
7954 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7957 // -----------------------------------------------------------
7958 // 1a. Collect nodes of existing faces
7959 // and build set of face nodes in order to detect missing
7960 // faces corresponing to sides of volumes
7961 // -----------------------------------------------------------
7963 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7965 // loop on the given element of a side
7966 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7967 //const SMDS_MeshElement* elem = *eIt;
7968 const SMDS_MeshElement* elem = *eIt;
7969 if ( elem->GetType() == SMDSAbs_Face ) {
7970 faceSet->insert( elem );
7971 set <const SMDS_MeshNode*> faceNodeSet;
7972 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7973 while ( nodeIt->more() ) {
7974 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7975 nodeSet->insert( n );
7976 faceNodeSet.insert( n );
7978 setOfFaceNodeSet.insert( faceNodeSet );
7980 else if ( elem->GetType() == SMDSAbs_Volume )
7981 volSet->insert( elem );
7983 // ------------------------------------------------------------------------------
7984 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
7985 // ------------------------------------------------------------------------------
7987 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7988 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7989 while ( fIt->more() ) { // loop on faces sharing a node
7990 const SMDS_MeshElement* f = fIt->next();
7991 if ( faceSet->find( f ) == faceSet->end() ) {
7992 // check if all nodes are in nodeSet and
7993 // complete setOfFaceNodeSet if they are
7994 set <const SMDS_MeshNode*> faceNodeSet;
7995 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7996 bool allInSet = true;
7997 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7998 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7999 if ( nodeSet->find( n ) == nodeSet->end() )
8002 faceNodeSet.insert( n );
8005 faceSet->insert( f );
8006 setOfFaceNodeSet.insert( faceNodeSet );
8012 // -------------------------------------------------------------------------
8013 // 1c. Create temporary faces representing sides of volumes if correspondent
8014 // face does not exist
8015 // -------------------------------------------------------------------------
8017 if ( !volSet->empty() ) {
8018 //int nodeSetSize = nodeSet->size();
8020 // loop on given volumes
8021 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8022 SMDS_VolumeTool vol (*vIt);
8023 // loop on volume faces: find free faces
8024 // --------------------------------------
8025 list<const SMDS_MeshElement* > freeFaceList;
8026 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8027 if ( !vol.IsFreeFace( iFace ))
8029 // check if there is already a face with same nodes in a face set
8030 const SMDS_MeshElement* aFreeFace = 0;
8031 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8032 int nbNodes = vol.NbFaceNodes( iFace );
8033 set <const SMDS_MeshNode*> faceNodeSet;
8034 vol.GetFaceNodes( iFace, faceNodeSet );
8035 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8037 // no such a face is given but it still can exist, check it
8038 if ( nbNodes == 3 ) {
8039 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8041 else if ( nbNodes == 4 ) {
8042 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8045 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8046 aFreeFace = aMesh->FindFace(poly_nodes);
8050 // create a temporary face
8051 if ( nbNodes == 3 ) {
8052 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8054 else if ( nbNodes == 4 ) {
8055 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8058 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8059 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8063 freeFaceList.push_back( aFreeFace );
8065 } // loop on faces of a volume
8067 // choose one of several free faces
8068 // --------------------------------------
8069 if ( freeFaceList.size() > 1 ) {
8070 // choose a face having max nb of nodes shared by other elems of a side
8071 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8072 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8073 while ( fIt != freeFaceList.end() ) { // loop on free faces
8074 int nbSharedNodes = 0;
8075 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8076 while ( nodeIt->more() ) { // loop on free face nodes
8077 const SMDS_MeshNode* n =
8078 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8079 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8080 while ( invElemIt->more() ) {
8081 const SMDS_MeshElement* e = invElemIt->next();
8082 if ( faceSet->find( e ) != faceSet->end() )
8084 if ( elemSet->find( e ) != elemSet->end() )
8088 if ( nbSharedNodes >= maxNbNodes ) {
8089 maxNbNodes = nbSharedNodes;
8093 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8095 if ( freeFaceList.size() > 1 )
8097 // could not choose one face, use another way
8098 // choose a face most close to the bary center of the opposite side
8099 gp_XYZ aBC( 0., 0., 0. );
8100 set <const SMDS_MeshNode*> addedNodes;
8101 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8102 eIt = elemSet2->begin();
8103 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8104 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8105 while ( nodeIt->more() ) { // loop on free face nodes
8106 const SMDS_MeshNode* n =
8107 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8108 if ( addedNodes.insert( n ).second )
8109 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8112 aBC /= addedNodes.size();
8113 double minDist = DBL_MAX;
8114 fIt = freeFaceList.begin();
8115 while ( fIt != freeFaceList.end() ) { // loop on free faces
8117 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8118 while ( nodeIt->more() ) { // loop on free face nodes
8119 const SMDS_MeshNode* n =
8120 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8121 gp_XYZ p( n->X(),n->Y(),n->Z() );
8122 dist += ( aBC - p ).SquareModulus();
8124 if ( dist < minDist ) {
8126 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8129 fIt = freeFaceList.erase( fIt++ );
8132 } // choose one of several free faces of a volume
8134 if ( freeFaceList.size() == 1 ) {
8135 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8136 faceSet->insert( aFreeFace );
8137 // complete a node set with nodes of a found free face
8138 // for ( iNode = 0; iNode < ; iNode++ )
8139 // nodeSet->insert( fNodes[ iNode ] );
8142 } // loop on volumes of a side
8144 // // complete a set of faces if new nodes in a nodeSet appeared
8145 // // ----------------------------------------------------------
8146 // if ( nodeSetSize != nodeSet->size() ) {
8147 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8148 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8149 // while ( fIt->more() ) { // loop on faces sharing a node
8150 // const SMDS_MeshElement* f = fIt->next();
8151 // if ( faceSet->find( f ) == faceSet->end() ) {
8152 // // check if all nodes are in nodeSet and
8153 // // complete setOfFaceNodeSet if they are
8154 // set <const SMDS_MeshNode*> faceNodeSet;
8155 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8156 // bool allInSet = true;
8157 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8158 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8159 // if ( nodeSet->find( n ) == nodeSet->end() )
8160 // allInSet = false;
8162 // faceNodeSet.insert( n );
8164 // if ( allInSet ) {
8165 // faceSet->insert( f );
8166 // setOfFaceNodeSet.insert( faceNodeSet );
8172 } // Create temporary faces, if there are volumes given
8175 if ( faceSet1.size() != faceSet2.size() ) {
8176 // delete temporary faces: they are in reverseElements of actual nodes
8177 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8178 while ( tmpFaceIt->more() )
8179 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8180 MESSAGE("Diff nb of faces");
8181 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8184 // ============================================================
8185 // 2. Find nodes to merge:
8186 // bind a node to remove to a node to put instead
8187 // ============================================================
8189 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
8190 if ( theFirstNode1 != theFirstNode2 )
8191 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
8192 if ( theSecondNode1 != theSecondNode2 )
8193 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
8195 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8196 set< long > linkIdSet; // links to process
8197 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
8199 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
8200 list< NLink > linkList[2];
8201 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8202 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8203 // loop on links in linkList; find faces by links and append links
8204 // of the found faces to linkList
8205 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8206 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8207 NLink link[] = { *linkIt[0], *linkIt[1] };
8208 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
8209 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
8212 // by links, find faces in the face sets,
8213 // and find indices of link nodes in the found faces;
8214 // in a face set, there is only one or no face sharing a link
8215 // ---------------------------------------------------------------
8217 const SMDS_MeshElement* face[] = { 0, 0 };
8218 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
8219 vector<const SMDS_MeshNode*> fnodes1(9);
8220 vector<const SMDS_MeshNode*> fnodes2(9);
8221 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
8222 vector<const SMDS_MeshNode*> notLinkNodes1(6);
8223 vector<const SMDS_MeshNode*> notLinkNodes2(6);
8224 int iLinkNode[2][2];
8225 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8226 const SMDS_MeshNode* n1 = link[iSide].first;
8227 const SMDS_MeshNode* n2 = link[iSide].second;
8228 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8229 set< const SMDS_MeshElement* > fMap;
8230 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
8231 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
8232 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8233 while ( fIt->more() ) { // loop on faces sharing a node
8234 const SMDS_MeshElement* f = fIt->next();
8235 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8236 ! fMap.insert( f ).second ) // f encounters twice
8238 if ( face[ iSide ] ) {
8239 MESSAGE( "2 faces per link " );
8240 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
8244 faceSet->erase( f );
8245 // get face nodes and find ones of a link
8250 fnodes1.resize(f->NbNodes()+1);
8251 notLinkNodes1.resize(f->NbNodes()-2);
8254 fnodes2.resize(f->NbNodes()+1);
8255 notLinkNodes2.resize(f->NbNodes()-2);
8258 if(!f->IsQuadratic()) {
8259 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
8260 while ( nIt->more() ) {
8261 const SMDS_MeshNode* n =
8262 static_cast<const SMDS_MeshNode*>( nIt->next() );
8264 iLinkNode[ iSide ][ 0 ] = iNode;
8266 else if ( n == n2 ) {
8267 iLinkNode[ iSide ][ 1 ] = iNode;
8269 //else if ( notLinkNodes[ iSide ][ 0 ] )
8270 // notLinkNodes[ iSide ][ 1 ] = n;
8272 // notLinkNodes[ iSide ][ 0 ] = n;
8276 notLinkNodes1[nbl] = n;
8277 //notLinkNodes1.push_back(n);
8279 notLinkNodes2[nbl] = n;
8280 //notLinkNodes2.push_back(n);
8282 //faceNodes[ iSide ][ iNode++ ] = n;
8284 fnodes1[iNode++] = n;
8287 fnodes2[iNode++] = n;
8291 else { // f->IsQuadratic()
8292 const SMDS_QuadraticFaceOfNodes* F =
8293 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
8294 // use special nodes iterator
8295 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8296 while ( anIter->more() ) {
8297 const SMDS_MeshNode* n =
8298 static_cast<const SMDS_MeshNode*>( anIter->next() );
8300 iLinkNode[ iSide ][ 0 ] = iNode;
8302 else if ( n == n2 ) {
8303 iLinkNode[ iSide ][ 1 ] = iNode;
8308 notLinkNodes1[nbl] = n;
8311 notLinkNodes2[nbl] = n;
8315 fnodes1[iNode++] = n;
8318 fnodes2[iNode++] = n;
8322 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
8324 fnodes1[iNode] = fnodes1[0];
8327 fnodes2[iNode] = fnodes1[0];
8334 // check similarity of elements of the sides
8335 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8336 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8337 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8338 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8341 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8343 break; // do not return because it s necessary to remove tmp faces
8346 // set nodes to merge
8347 // -------------------
8349 if ( face[0] && face[1] ) {
8350 int nbNodes = face[0]->NbNodes();
8351 if ( nbNodes != face[1]->NbNodes() ) {
8352 MESSAGE("Diff nb of face nodes");
8353 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8354 break; // do not return because it s necessary to remove tmp faces
8356 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
8357 if ( nbNodes == 3 ) {
8358 //nReplaceMap.insert( TNodeNodeMap::value_type
8359 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8360 nReplaceMap.insert( TNodeNodeMap::value_type
8361 ( notLinkNodes1[0], notLinkNodes2[0] ));
8364 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8365 // analyse link orientation in faces
8366 int i1 = iLinkNode[ iSide ][ 0 ];
8367 int i2 = iLinkNode[ iSide ][ 1 ];
8368 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
8369 // if notLinkNodes are the first and the last ones, then
8370 // their order does not correspond to the link orientation
8371 if (( i1 == 1 && i2 == 2 ) ||
8372 ( i1 == 2 && i2 == 1 ))
8373 reverse[ iSide ] = !reverse[ iSide ];
8375 if ( reverse[0] == reverse[1] ) {
8376 //nReplaceMap.insert( TNodeNodeMap::value_type
8377 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8378 //nReplaceMap.insert( TNodeNodeMap::value_type
8379 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
8380 for(int nn=0; nn<nbNodes-2; nn++) {
8381 nReplaceMap.insert( TNodeNodeMap::value_type
8382 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
8386 //nReplaceMap.insert( TNodeNodeMap::value_type
8387 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
8388 //nReplaceMap.insert( TNodeNodeMap::value_type
8389 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
8390 for(int nn=0; nn<nbNodes-2; nn++) {
8391 nReplaceMap.insert( TNodeNodeMap::value_type
8392 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
8397 // add other links of the faces to linkList
8398 // -----------------------------------------
8400 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
8401 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8402 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
8403 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
8404 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
8405 if ( !iter_isnew.second ) { // already in a set: no need to process
8406 linkIdSet.erase( iter_isnew.first );
8408 else // new in set == encountered for the first time: add
8410 //const SMDS_MeshNode* n1 = nodes[ iNode ];
8411 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
8412 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
8413 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
8414 linkList[0].push_back ( NLink( n1, n2 ));
8415 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8419 } // loop on link lists
8421 if ( aResult == SEW_OK &&
8422 ( linkIt[0] != linkList[0].end() ||
8423 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
8424 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
8425 " " << (faceSetPtr[1]->empty()));
8426 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8429 // ====================================================================
8430 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8431 // ====================================================================
8433 // delete temporary faces: they are in reverseElements of actual nodes
8434 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8435 while ( tmpFaceIt->more() )
8436 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8438 if ( aResult != SEW_OK)
8441 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
8442 // loop on nodes replacement map
8443 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
8444 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
8445 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
8446 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
8447 nodeIDsToRemove.push_back( nToRemove->GetID() );
8448 // loop on elements sharing nToRemove
8449 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
8450 while ( invElemIt->more() ) {
8451 const SMDS_MeshElement* e = invElemIt->next();
8452 // get a new suite of nodes: make replacement
8453 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
8454 vector< const SMDS_MeshNode*> nodes( nbNodes );
8455 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8456 while ( nIt->more() ) {
8457 const SMDS_MeshNode* n =
8458 static_cast<const SMDS_MeshNode*>( nIt->next() );
8459 nnIt = nReplaceMap.find( n );
8460 if ( nnIt != nReplaceMap.end() ) {
8466 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8467 // elemIDsToRemove.push_back( e->GetID() );
8470 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8474 Remove( nodeIDsToRemove, true );
8479 //================================================================================
8481 * \brief Find corresponding nodes in two sets of faces
8482 * \param theSide1 - first face set
8483 * \param theSide2 - second first face
8484 * \param theFirstNode1 - a boundary node of set 1
8485 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8486 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8487 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8488 * \param nReplaceMap - output map of corresponding nodes
8489 * \retval bool - is a success or not
8491 //================================================================================
8494 //#define DEBUG_MATCHING_NODES
8497 SMESH_MeshEditor::Sew_Error
8498 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8499 set<const SMDS_MeshElement*>& theSide2,
8500 const SMDS_MeshNode* theFirstNode1,
8501 const SMDS_MeshNode* theFirstNode2,
8502 const SMDS_MeshNode* theSecondNode1,
8503 const SMDS_MeshNode* theSecondNode2,
8504 TNodeNodeMap & nReplaceMap)
8506 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8508 nReplaceMap.clear();
8509 if ( theFirstNode1 != theFirstNode2 )
8510 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8511 if ( theSecondNode1 != theSecondNode2 )
8512 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8514 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8515 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8517 list< NLink > linkList[2];
8518 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8519 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8521 // loop on links in linkList; find faces by links and append links
8522 // of the found faces to linkList
8523 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8524 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8525 NLink link[] = { *linkIt[0], *linkIt[1] };
8526 if ( linkSet.find( link[0] ) == linkSet.end() )
8529 // by links, find faces in the face sets,
8530 // and find indices of link nodes in the found faces;
8531 // in a face set, there is only one or no face sharing a link
8532 // ---------------------------------------------------------------
8534 const SMDS_MeshElement* face[] = { 0, 0 };
8535 list<const SMDS_MeshNode*> notLinkNodes[2];
8536 //bool reverse[] = { false, false }; // order of notLinkNodes
8538 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8540 const SMDS_MeshNode* n1 = link[iSide].first;
8541 const SMDS_MeshNode* n2 = link[iSide].second;
8542 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8543 set< const SMDS_MeshElement* > facesOfNode1;
8544 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8546 // during a loop of the first node, we find all faces around n1,
8547 // during a loop of the second node, we find one face sharing both n1 and n2
8548 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8549 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8550 while ( fIt->more() ) { // loop on faces sharing a node
8551 const SMDS_MeshElement* f = fIt->next();
8552 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8553 ! facesOfNode1.insert( f ).second ) // f encounters twice
8555 if ( face[ iSide ] ) {
8556 MESSAGE( "2 faces per link " );
8557 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8560 faceSet->erase( f );
8562 // get not link nodes
8563 int nbN = f->NbNodes();
8564 if ( f->IsQuadratic() )
8566 nbNodes[ iSide ] = nbN;
8567 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8568 int i1 = f->GetNodeIndex( n1 );
8569 int i2 = f->GetNodeIndex( n2 );
8570 int iEnd = nbN, iBeg = -1, iDelta = 1;
8571 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8573 std::swap( iEnd, iBeg ); iDelta = -1;
8578 if ( i == iEnd ) i = iBeg + iDelta;
8579 if ( i == i1 ) break;
8580 nodes.push_back ( f->GetNode( i ) );
8586 // check similarity of elements of the sides
8587 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8588 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8589 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8590 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8593 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8597 // set nodes to merge
8598 // -------------------
8600 if ( face[0] && face[1] ) {
8601 if ( nbNodes[0] != nbNodes[1] ) {
8602 MESSAGE("Diff nb of face nodes");
8603 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8605 #ifdef DEBUG_MATCHING_NODES
8606 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8607 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8608 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8610 int nbN = nbNodes[0];
8612 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8613 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8614 for ( int i = 0 ; i < nbN - 2; ++i ) {
8615 #ifdef DEBUG_MATCHING_NODES
8616 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8618 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8622 // add other links of the face 1 to linkList
8623 // -----------------------------------------
8625 const SMDS_MeshElement* f0 = face[0];
8626 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8627 for ( int i = 0; i < nbN; i++ )
8629 const SMDS_MeshNode* n2 = f0->GetNode( i );
8630 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8631 linkSet.insert( SMESH_TLink( n1, n2 ));
8632 if ( !iter_isnew.second ) { // already in a set: no need to process
8633 linkSet.erase( iter_isnew.first );
8635 else // new in set == encountered for the first time: add
8637 #ifdef DEBUG_MATCHING_NODES
8638 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8639 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8641 linkList[0].push_back ( NLink( n1, n2 ));
8642 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8647 } // loop on link lists
8653 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8654 \param theElems - the list of elements (edges or faces) to be replicated
8655 The nodes for duplication could be found from these elements
8656 \param theNodesNot - list of nodes to NOT replicate
8657 \param theAffectedElems - the list of elements (cells and edges) to which the
8658 replicated nodes should be associated to.
8659 \return TRUE if operation has been completed successfully, FALSE otherwise
8661 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
8662 const TIDSortedElemSet& theNodesNot,
8663 const TIDSortedElemSet& theAffectedElems )
8665 myLastCreatedElems.Clear();
8666 myLastCreatedNodes.Clear();
8668 if ( theElems.size() == 0 )
8671 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8676 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8677 // duplicate elements and nodes
8678 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
8679 // replce nodes by duplications
8680 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
8685 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8686 \param theMeshDS - mesh instance
8687 \param theElems - the elements replicated or modified (nodes should be changed)
8688 \param theNodesNot - nodes to NOT replicate
8689 \param theNodeNodeMap - relation of old node to new created node
8690 \param theIsDoubleElem - flag os to replicate element or modify
8691 \return TRUE if operation has been completed successfully, FALSE otherwise
8693 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
8694 const TIDSortedElemSet& theElems,
8695 const TIDSortedElemSet& theNodesNot,
8696 std::map< const SMDS_MeshNode*,
8697 const SMDS_MeshNode* >& theNodeNodeMap,
8698 const bool theIsDoubleElem )
8700 // iterate on through element and duplicate them (by nodes duplication)
8702 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8703 for ( ; elemItr != theElems.end(); ++elemItr )
8705 const SMDS_MeshElement* anElem = *elemItr;
8709 bool isDuplicate = false;
8710 // duplicate nodes to duplicate element
8711 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
8712 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8714 while ( anIter->more() )
8717 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8718 SMDS_MeshNode* aNewNode = aCurrNode;
8719 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
8720 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
8721 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
8724 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
8725 theNodeNodeMap[ aCurrNode ] = aNewNode;
8726 myLastCreatedNodes.Append( aNewNode );
8728 isDuplicate |= (aCurrNode == aNewNode);
8729 newNodes[ ind++ ] = aNewNode;
8734 if ( theIsDoubleElem )
8735 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
8737 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
8745 \brief Check if element located inside shape
8746 \return TRUE if IN or ON shape, FALSE otherwise
8749 static bool isInside(const SMDS_MeshElement* theElem,
8750 BRepClass3d_SolidClassifier& theBsc3d,
8751 const double theTol)
8753 gp_XYZ centerXYZ (0, 0, 0);
8754 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
8755 while (aNodeItr->more())
8757 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
8758 centerXYZ += gp_XYZ(aNode->X(), aNode->Y(), aNode->Z());
8760 gp_Pnt aPnt(centerXYZ);
8761 theBsc3d.Perform(aPnt, theTol);
8762 TopAbs_State aState = theBsc3d.State();
8763 return (aState == TopAbs_IN || aState == TopAbs_ON );
8767 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8768 \param theElems - group of of elements (edges or faces) to be replicated
8769 \param theNodesNot - group of nodes not to replicated
8770 \param theShape - shape to detect affected elements (element which geometric center
8771 located on or inside shape).
8772 The replicated nodes should be associated to affected elements.
8773 \return TRUE if operation has been completed successfully, FALSE otherwise
8776 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
8777 const TIDSortedElemSet& theNodesNot,
8778 const TopoDS_Shape& theShape )
8780 SMESHDS_Mesh* aMesh = GetMeshDS();
8783 if ( theShape.IsNull() )
8786 const double aTol = Precision::Confusion();
8787 BRepClass3d_SolidClassifier bsc3d(theShape);
8788 bsc3d.PerformInfinitePoint(aTol);
8790 // iterates on indicated elements and get elements by back references from their nodes
8791 TIDSortedElemSet anAffected;
8792 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8793 for ( ; elemItr != theElems.end(); ++elemItr )
8795 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
8799 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
8800 while ( nodeItr->more() )
8802 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
8803 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
8805 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
8806 while ( backElemItr->more() )
8808 SMDS_MeshElement* curElem = (SMDS_MeshElement*)backElemItr->next();
8809 if ( curElem && theElems.find(curElem) == theElems.end() &&
8810 isInside( curElem, bsc3d, aTol ) )
8811 anAffected.insert( curElem );
8815 return DoubleNodes( theElems, theNodesNot, anAffected );