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 <BRepAdaptor_Surface.hxx>
50 #include <BRepClass3d_SolidClassifier.hxx>
51 #include <BRep_Tool.hxx>
53 #include <Extrema_GenExtPS.hxx>
54 #include <Extrema_POnSurf.hxx>
55 #include <Geom2d_Curve.hxx>
56 #include <GeomAdaptor_Surface.hxx>
57 #include <Geom_Curve.hxx>
58 #include <Geom_Surface.hxx>
59 #include <Precision.hxx>
60 #include <TColStd_ListOfInteger.hxx>
61 #include <TopAbs_State.hxx>
63 #include <TopExp_Explorer.hxx>
64 #include <TopTools_ListIteratorOfListOfShape.hxx>
65 #include <TopTools_ListOfShape.hxx>
66 #include <TopTools_SequenceOfShape.hxx>
68 #include <TopoDS_Face.hxx>
74 #include <gp_Trsf.hxx>
85 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
88 using namespace SMESH::Controls;
90 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
91 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
92 //typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> > TNodeOfNodeVecMap;
93 //typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr;
94 //typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> > TElemOfVecOfMapNodesMap;
96 //=======================================================================
98 * \brief SMDS_MeshNode -> gp_XYZ convertor
100 //=======================================================================
102 struct TNodeXYZ : public gp_XYZ
104 TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {}
105 double Distance( const SMDS_MeshNode* n )
107 return gp_Vec( *this, TNodeXYZ( n )).Magnitude();
109 double SquareDistance( const SMDS_MeshNode* n )
111 return gp_Vec( *this, TNodeXYZ( n )).SquareMagnitude();
115 //=======================================================================
116 //function : SMESH_MeshEditor
118 //=======================================================================
120 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
121 :myMesh( theMesh ) // theMesh may be NULL
125 //=======================================================================
129 //=======================================================================
132 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
133 const SMDSAbs_ElementType type,
137 SMDS_MeshElement* e = 0;
138 int nbnode = node.size();
139 SMESHDS_Mesh* mesh = GetMeshDS();
143 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
144 else e = mesh->AddEdge (node[0], node[1] );
145 else if ( nbnode == 3 )
146 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
147 else e = mesh->AddEdge (node[0], node[1], node[2] );
152 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
153 else e = mesh->AddFace (node[0], node[1], node[2] );
154 else if (nbnode == 4)
155 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
156 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
157 else if (nbnode == 6)
158 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
159 node[4], node[5], ID);
160 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
162 else if (nbnode == 8)
163 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
164 node[4], node[5], node[6], node[7], ID);
165 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
166 node[4], node[5], node[6], node[7] );
168 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
169 else e = mesh->AddPolygonalFace (node );
175 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
176 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
177 else if (nbnode == 5)
178 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
182 else if (nbnode == 6)
183 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
184 node[4], node[5], ID);
185 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
187 else if (nbnode == 8)
188 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7], ID);
190 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
191 node[4], node[5], node[6], node[7] );
192 else if (nbnode == 10)
193 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
194 node[4], node[5], node[6], node[7],
195 node[8], node[9], ID);
196 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
197 node[4], node[5], node[6], node[7],
199 else if (nbnode == 13)
200 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201 node[4], node[5], node[6], node[7],
202 node[8], node[9], node[10],node[11],
204 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
205 node[4], node[5], node[6], node[7],
206 node[8], node[9], node[10],node[11],
208 else if (nbnode == 15)
209 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
210 node[4], node[5], node[6], node[7],
211 node[8], node[9], node[10],node[11],
212 node[12],node[13],node[14],ID);
213 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
214 node[4], node[5], node[6], node[7],
215 node[8], node[9], node[10],node[11],
216 node[12],node[13],node[14] );
217 else if (nbnode == 20)
218 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219 node[4], node[5], node[6], node[7],
220 node[8], node[9], node[10],node[11],
221 node[12],node[13],node[14],node[15],
222 node[16],node[17],node[18],node[19],ID);
223 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
224 node[4], node[5], node[6], node[7],
225 node[8], node[9], node[10],node[11],
226 node[12],node[13],node[14],node[15],
227 node[16],node[17],node[18],node[19] );
233 //=======================================================================
237 //=======================================================================
239 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
240 const SMDSAbs_ElementType type,
244 vector<const SMDS_MeshNode*> nodes;
245 nodes.reserve( nodeIDs.size() );
246 vector<int>::const_iterator id = nodeIDs.begin();
247 while ( id != nodeIDs.end() ) {
248 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
249 nodes.push_back( node );
253 return AddElement( nodes, type, isPoly, ID );
256 //=======================================================================
258 //purpose : Remove a node or an element.
259 // Modify a compute state of sub-meshes which become empty
260 //=======================================================================
262 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
265 myLastCreatedElems.Clear();
266 myLastCreatedNodes.Clear();
268 SMESHDS_Mesh* aMesh = GetMeshDS();
269 set< SMESH_subMesh *> smmap;
271 list<int>::const_iterator it = theIDs.begin();
272 for ( ; it != theIDs.end(); it++ ) {
273 const SMDS_MeshElement * elem;
275 elem = aMesh->FindNode( *it );
277 elem = aMesh->FindElement( *it );
281 // Notify VERTEX sub-meshes about modification
283 const SMDS_MeshNode* node = cast2Node( elem );
284 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
285 if ( int aShapeID = node->GetPosition()->GetShapeId() )
286 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
289 // Find sub-meshes to notify about modification
290 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
291 // while ( nodeIt->more() ) {
292 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
293 // const SMDS_PositionPtr& aPosition = node->GetPosition();
294 // if ( aPosition.get() ) {
295 // if ( int aShapeID = aPosition->GetShapeId() ) {
296 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
297 // smmap.insert( sm );
304 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
306 aMesh->RemoveElement( elem );
309 // Notify sub-meshes about modification
310 if ( !smmap.empty() ) {
311 set< SMESH_subMesh *>::iterator smIt;
312 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
313 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
316 // // Check if the whole mesh becomes empty
317 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
318 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
323 //=======================================================================
324 //function : FindShape
325 //purpose : Return an index of the shape theElem is on
326 // or zero if a shape not found
327 //=======================================================================
329 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
331 myLastCreatedElems.Clear();
332 myLastCreatedNodes.Clear();
334 SMESHDS_Mesh * aMesh = GetMeshDS();
335 if ( aMesh->ShapeToMesh().IsNull() )
338 if ( theElem->GetType() == SMDSAbs_Node ) {
339 const SMDS_PositionPtr& aPosition =
340 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
341 if ( aPosition.get() )
342 return aPosition->GetShapeId();
347 TopoDS_Shape aShape; // the shape a node is on
348 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
349 while ( nodeIt->more() ) {
350 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
351 const SMDS_PositionPtr& aPosition = node->GetPosition();
352 if ( aPosition.get() ) {
353 int aShapeID = aPosition->GetShapeId();
354 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
356 if ( sm->Contains( theElem ))
358 if ( aShape.IsNull() )
359 aShape = aMesh->IndexToShape( aShapeID );
362 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
367 // None of nodes is on a proper shape,
368 // find the shape among ancestors of aShape on which a node is
369 if ( aShape.IsNull() ) {
370 //MESSAGE ("::FindShape() - NONE node is on shape")
373 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
374 for ( ; ancIt.More(); ancIt.Next() ) {
375 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
376 if ( sm && sm->Contains( theElem ))
377 return aMesh->ShapeToIndex( ancIt.Value() );
380 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
384 //=======================================================================
385 //function : IsMedium
387 //=======================================================================
389 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
390 const SMDSAbs_ElementType typeToCheck)
392 bool isMedium = false;
393 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
394 while (it->more() && !isMedium ) {
395 const SMDS_MeshElement* elem = it->next();
396 isMedium = elem->IsMediumNode(node);
401 //=======================================================================
402 //function : ShiftNodesQuadTria
404 // Shift nodes in the array corresponded to quadratic triangle
405 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
406 //=======================================================================
407 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
409 const SMDS_MeshNode* nd1 = aNodes[0];
410 aNodes[0] = aNodes[1];
411 aNodes[1] = aNodes[2];
413 const SMDS_MeshNode* nd2 = aNodes[3];
414 aNodes[3] = aNodes[4];
415 aNodes[4] = aNodes[5];
419 //=======================================================================
420 //function : GetNodesFromTwoTria
422 // Shift nodes in the array corresponded to quadratic triangle
423 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
424 //=======================================================================
425 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
426 const SMDS_MeshElement * theTria2,
427 const SMDS_MeshNode* N1[],
428 const SMDS_MeshNode* N2[])
430 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
433 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
436 if(it->more()) return false;
437 it = theTria2->nodesIterator();
440 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
443 if(it->more()) return false;
445 int sames[3] = {-1,-1,-1};
457 if(nbsames!=2) return false;
459 ShiftNodesQuadTria(N1);
461 ShiftNodesQuadTria(N1);
464 i = sames[0] + sames[1] + sames[2];
466 ShiftNodesQuadTria(N2);
468 // now we receive following N1 and N2 (using numeration as above image)
469 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
470 // i.e. first nodes from both arrays determ new diagonal
474 //=======================================================================
475 //function : InverseDiag
476 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
477 // but having other common link.
478 // Return False if args are improper
479 //=======================================================================
481 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
482 const SMDS_MeshElement * theTria2 )
484 myLastCreatedElems.Clear();
485 myLastCreatedNodes.Clear();
487 if (!theTria1 || !theTria2)
490 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
491 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
494 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
495 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
499 // put nodes in array and find out indices of the same ones
500 const SMDS_MeshNode* aNodes [6];
501 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
503 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
504 while ( it->more() ) {
505 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
507 if ( i > 2 ) // theTria2
508 // find same node of theTria1
509 for ( int j = 0; j < 3; j++ )
510 if ( aNodes[ i ] == aNodes[ j ]) {
519 return false; // theTria1 is not a triangle
520 it = theTria2->nodesIterator();
522 if ( i == 6 && it->more() )
523 return false; // theTria2 is not a triangle
526 // find indices of 1,2 and of A,B in theTria1
527 int iA = 0, iB = 0, i1 = 0, i2 = 0;
528 for ( i = 0; i < 6; i++ ) {
529 if ( sameInd [ i ] == 0 )
536 // nodes 1 and 2 should not be the same
537 if ( aNodes[ i1 ] == aNodes[ i2 ] )
541 aNodes[ iA ] = aNodes[ i2 ];
543 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
545 //MESSAGE( theTria1 << theTria2 );
547 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
548 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
550 //MESSAGE( theTria1 << theTria2 );
554 } // end if(F1 && F2)
556 // check case of quadratic faces
557 const SMDS_QuadraticFaceOfNodes* QF1 =
558 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
559 if(!QF1) return false;
560 const SMDS_QuadraticFaceOfNodes* QF2 =
561 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
562 if(!QF2) return false;
565 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
566 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
574 const SMDS_MeshNode* N1 [6];
575 const SMDS_MeshNode* N2 [6];
576 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
578 // now we receive following N1 and N2 (using numeration as above image)
579 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
580 // i.e. first nodes from both arrays determ new diagonal
582 const SMDS_MeshNode* N1new [6];
583 const SMDS_MeshNode* N2new [6];
596 // replaces nodes in faces
597 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
598 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
603 //=======================================================================
604 //function : findTriangles
605 //purpose : find triangles sharing theNode1-theNode2 link
606 //=======================================================================
608 static bool findTriangles(const SMDS_MeshNode * theNode1,
609 const SMDS_MeshNode * theNode2,
610 const SMDS_MeshElement*& theTria1,
611 const SMDS_MeshElement*& theTria2)
613 if ( !theNode1 || !theNode2 ) return false;
615 theTria1 = theTria2 = 0;
617 set< const SMDS_MeshElement* > emap;
618 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
620 const SMDS_MeshElement* elem = it->next();
621 if ( elem->NbNodes() == 3 )
624 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
626 const SMDS_MeshElement* elem = it->next();
627 if ( emap.find( elem ) != emap.end() )
629 // theTria1 must be element with minimum ID
630 if( theTria1->GetID() < elem->GetID() ) {
643 return ( theTria1 && theTria2 );
646 //=======================================================================
647 //function : InverseDiag
648 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
649 // with ones built on the same 4 nodes but having other common link.
650 // Return false if proper faces not found
651 //=======================================================================
653 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
654 const SMDS_MeshNode * theNode2)
656 myLastCreatedElems.Clear();
657 myLastCreatedNodes.Clear();
659 MESSAGE( "::InverseDiag()" );
661 const SMDS_MeshElement *tr1, *tr2;
662 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
665 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
666 //if (!F1) return false;
667 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
668 //if (!F2) return false;
671 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
672 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
676 // put nodes in array
677 // and find indices of 1,2 and of A in tr1 and of B in tr2
678 int i, iA1 = 0, i1 = 0;
679 const SMDS_MeshNode* aNodes1 [3];
680 SMDS_ElemIteratorPtr it;
681 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
682 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
683 if ( aNodes1[ i ] == theNode1 )
684 iA1 = i; // node A in tr1
685 else if ( aNodes1[ i ] != theNode2 )
689 const SMDS_MeshNode* aNodes2 [3];
690 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
691 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
692 if ( aNodes2[ i ] == theNode2 )
693 iB2 = i; // node B in tr2
694 else if ( aNodes2[ i ] != theNode1 )
698 // nodes 1 and 2 should not be the same
699 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
703 aNodes1[ iA1 ] = aNodes2[ i2 ];
705 aNodes2[ iB2 ] = aNodes1[ i1 ];
707 //MESSAGE( tr1 << tr2 );
709 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
710 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
712 //MESSAGE( tr1 << tr2 );
717 // check case of quadratic faces
718 const SMDS_QuadraticFaceOfNodes* QF1 =
719 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
720 if(!QF1) return false;
721 const SMDS_QuadraticFaceOfNodes* QF2 =
722 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
723 if(!QF2) return false;
724 return InverseDiag(tr1,tr2);
727 //=======================================================================
728 //function : getQuadrangleNodes
729 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
730 // fusion of triangles tr1 and tr2 having shared link on
731 // theNode1 and theNode2
732 //=======================================================================
734 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
735 const SMDS_MeshNode * theNode1,
736 const SMDS_MeshNode * theNode2,
737 const SMDS_MeshElement * tr1,
738 const SMDS_MeshElement * tr2 )
740 if( tr1->NbNodes() != tr2->NbNodes() )
742 // find the 4-th node to insert into tr1
743 const SMDS_MeshNode* n4 = 0;
744 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
746 while ( !n4 && i<3 ) {
747 const SMDS_MeshNode * n = cast2Node( it->next() );
749 bool isDiag = ( n == theNode1 || n == theNode2 );
753 // Make an array of nodes to be in a quadrangle
754 int iNode = 0, iFirstDiag = -1;
755 it = tr1->nodesIterator();
758 const SMDS_MeshNode * n = cast2Node( it->next() );
760 bool isDiag = ( n == theNode1 || n == theNode2 );
762 if ( iFirstDiag < 0 )
764 else if ( iNode - iFirstDiag == 1 )
765 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
767 else if ( n == n4 ) {
768 return false; // tr1 and tr2 should not have all the same nodes
770 theQuadNodes[ iNode++ ] = n;
772 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
773 theQuadNodes[ iNode ] = n4;
778 //=======================================================================
779 //function : DeleteDiag
780 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
781 // with a quadrangle built on the same 4 nodes.
782 // Return false if proper faces not found
783 //=======================================================================
785 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
786 const SMDS_MeshNode * theNode2)
788 myLastCreatedElems.Clear();
789 myLastCreatedNodes.Clear();
791 MESSAGE( "::DeleteDiag()" );
793 const SMDS_MeshElement *tr1, *tr2;
794 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
797 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
798 //if (!F1) return false;
799 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
800 //if (!F2) return false;
803 const SMDS_MeshNode* aNodes [ 4 ];
804 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
807 //MESSAGE( endl << tr1 << tr2 );
809 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
810 myLastCreatedElems.Append(tr1);
811 GetMeshDS()->RemoveElement( tr2 );
813 //MESSAGE( endl << tr1 );
818 // check case of quadratic faces
819 const SMDS_QuadraticFaceOfNodes* QF1 =
820 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
821 if(!QF1) return false;
822 const SMDS_QuadraticFaceOfNodes* QF2 =
823 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
824 if(!QF2) return false;
827 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
828 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
836 const SMDS_MeshNode* N1 [6];
837 const SMDS_MeshNode* N2 [6];
838 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
840 // now we receive following N1 and N2 (using numeration as above image)
841 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
842 // i.e. first nodes from both arrays determ new diagonal
844 const SMDS_MeshNode* aNodes[8];
854 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
855 myLastCreatedElems.Append(tr1);
856 GetMeshDS()->RemoveElement( tr2 );
858 // remove middle node (9)
859 GetMeshDS()->RemoveNode( N1[4] );
864 //=======================================================================
865 //function : Reorient
866 //purpose : Reverse theElement orientation
867 //=======================================================================
869 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
871 myLastCreatedElems.Clear();
872 myLastCreatedNodes.Clear();
876 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
877 if ( !it || !it->more() )
880 switch ( theElem->GetType() ) {
884 if(!theElem->IsQuadratic()) {
885 int i = theElem->NbNodes();
886 vector<const SMDS_MeshNode*> aNodes( i );
888 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
889 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
892 // quadratic elements
893 if(theElem->GetType()==SMDSAbs_Edge) {
894 vector<const SMDS_MeshNode*> aNodes(3);
895 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
896 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
897 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
898 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
901 int nbn = theElem->NbNodes();
902 vector<const SMDS_MeshNode*> aNodes(nbn);
903 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
905 for(; i<nbn/2; i++) {
906 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
908 for(i=0; i<nbn/2; i++) {
909 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
911 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
915 case SMDSAbs_Volume: {
916 if (theElem->IsPoly()) {
917 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
918 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
920 MESSAGE("Warning: bad volumic element");
924 int nbFaces = aPolyedre->NbFaces();
925 vector<const SMDS_MeshNode *> poly_nodes;
926 vector<int> quantities (nbFaces);
928 // reverse each face of the polyedre
929 for (int iface = 1; iface <= nbFaces; iface++) {
930 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
931 quantities[iface - 1] = nbFaceNodes;
933 for (inode = nbFaceNodes; inode >= 1; inode--) {
934 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
935 poly_nodes.push_back(curNode);
939 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
943 SMDS_VolumeTool vTool;
944 if ( !vTool.Set( theElem ))
947 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
956 //=======================================================================
957 //function : getBadRate
959 //=======================================================================
961 static double getBadRate (const SMDS_MeshElement* theElem,
962 SMESH::Controls::NumericalFunctorPtr& theCrit)
964 SMESH::Controls::TSequenceOfXYZ P;
965 if ( !theElem || !theCrit->GetPoints( theElem, P ))
967 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
968 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
971 //=======================================================================
972 //function : QuadToTri
973 //purpose : Cut quadrangles into triangles.
974 // theCrit is used to select a diagonal to cut
975 //=======================================================================
977 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
978 SMESH::Controls::NumericalFunctorPtr theCrit)
980 myLastCreatedElems.Clear();
981 myLastCreatedNodes.Clear();
983 MESSAGE( "::QuadToTri()" );
985 if ( !theCrit.get() )
988 SMESHDS_Mesh * aMesh = GetMeshDS();
990 Handle(Geom_Surface) surface;
991 SMESH_MesherHelper helper( *GetMesh() );
993 TIDSortedElemSet::iterator itElem;
994 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
995 const SMDS_MeshElement* elem = *itElem;
996 if ( !elem || elem->GetType() != SMDSAbs_Face )
998 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1001 // retrieve element nodes
1002 const SMDS_MeshNode* aNodes [8];
1003 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1005 while ( itN->more() )
1006 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1008 // compare two sets of possible triangles
1009 double aBadRate1, aBadRate2; // to what extent a set is bad
1010 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1011 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1012 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1014 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1015 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1016 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1018 int aShapeId = FindShape( elem );
1019 const SMDS_MeshElement* newElem = 0;
1021 if( !elem->IsQuadratic() ) {
1023 // split liner quadrangle
1025 if ( aBadRate1 <= aBadRate2 ) {
1026 // tr1 + tr2 is better
1027 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1028 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1031 // tr3 + tr4 is better
1032 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1033 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1038 // split quadratic quadrangle
1040 // get surface elem is on
1041 if ( aShapeId != helper.GetSubShapeID() ) {
1045 shape = aMesh->IndexToShape( aShapeId );
1046 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1047 TopoDS_Face face = TopoDS::Face( shape );
1048 surface = BRep_Tool::Surface( face );
1049 if ( !surface.IsNull() )
1050 helper.SetSubShape( shape );
1054 const SMDS_MeshNode* aNodes [8];
1055 const SMDS_MeshNode* inFaceNode = 0;
1056 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1058 while ( itN->more() ) {
1059 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1060 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1061 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1063 inFaceNode = aNodes[ i-1 ];
1066 // find middle point for (0,1,2,3)
1067 // and create a node in this point;
1069 if ( surface.IsNull() ) {
1071 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1075 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1078 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1080 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1082 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1083 myLastCreatedNodes.Append(newN);
1085 // create a new element
1086 const SMDS_MeshNode* N[6];
1087 if ( aBadRate1 <= aBadRate2 ) {
1094 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1095 aNodes[6], aNodes[7], newN );
1104 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1105 aNodes[7], aNodes[4], newN );
1107 aMesh->ChangeElementNodes( elem, N, 6 );
1111 // care of a new element
1113 myLastCreatedElems.Append(newElem);
1114 AddToSameGroups( newElem, elem, aMesh );
1116 // put a new triangle on the same shape
1118 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1123 //=======================================================================
1124 //function : BestSplit
1125 //purpose : Find better diagonal for cutting.
1126 //=======================================================================
1127 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1128 SMESH::Controls::NumericalFunctorPtr theCrit)
1130 myLastCreatedElems.Clear();
1131 myLastCreatedNodes.Clear();
1136 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1139 if( theQuad->NbNodes()==4 ||
1140 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1142 // retrieve element nodes
1143 const SMDS_MeshNode* aNodes [4];
1144 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1146 //while (itN->more())
1148 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1150 // compare two sets of possible triangles
1151 double aBadRate1, aBadRate2; // to what extent a set is bad
1152 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1153 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1154 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1156 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1157 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1158 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1160 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1161 return 1; // diagonal 1-3
1163 return 2; // diagonal 2-4
1168 //=======================================================================
1169 //function : AddToSameGroups
1170 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1171 //=======================================================================
1173 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1174 const SMDS_MeshElement* elemInGroups,
1175 SMESHDS_Mesh * aMesh)
1177 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1178 if (!groups.empty()) {
1179 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1180 for ( ; grIt != groups.end(); grIt++ ) {
1181 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1182 if ( group && group->Contains( elemInGroups ))
1183 group->SMDSGroup().Add( elemToAdd );
1189 //=======================================================================
1190 //function : RemoveElemFromGroups
1191 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1192 //=======================================================================
1193 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1194 SMESHDS_Mesh * aMesh)
1196 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1197 if (!groups.empty())
1199 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1200 for (; GrIt != groups.end(); GrIt++)
1202 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1203 if (!grp || grp->IsEmpty()) continue;
1204 grp->SMDSGroup().Remove(removeelem);
1209 //=======================================================================
1210 //function : ReplaceElemInGroups
1211 //purpose : replace elemToRm by elemToAdd in the all groups
1212 //=======================================================================
1214 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1215 const SMDS_MeshElement* elemToAdd,
1216 SMESHDS_Mesh * aMesh)
1218 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1219 if (!groups.empty()) {
1220 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1221 for ( ; grIt != groups.end(); grIt++ ) {
1222 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1223 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1224 group->SMDSGroup().Add( elemToAdd );
1229 //=======================================================================
1230 //function : QuadToTri
1231 //purpose : Cut quadrangles into triangles.
1232 // theCrit is used to select a diagonal to cut
1233 //=======================================================================
1235 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1236 const bool the13Diag)
1238 myLastCreatedElems.Clear();
1239 myLastCreatedNodes.Clear();
1241 MESSAGE( "::QuadToTri()" );
1243 SMESHDS_Mesh * aMesh = GetMeshDS();
1245 Handle(Geom_Surface) surface;
1246 SMESH_MesherHelper helper( *GetMesh() );
1248 TIDSortedElemSet::iterator itElem;
1249 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1250 const SMDS_MeshElement* elem = *itElem;
1251 if ( !elem || elem->GetType() != SMDSAbs_Face )
1253 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1254 if(!isquad) continue;
1256 if(elem->NbNodes()==4) {
1257 // retrieve element nodes
1258 const SMDS_MeshNode* aNodes [4];
1259 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1261 while ( itN->more() )
1262 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1264 int aShapeId = FindShape( elem );
1265 const SMDS_MeshElement* newElem = 0;
1267 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1268 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1271 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1272 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1274 myLastCreatedElems.Append(newElem);
1275 // put a new triangle on the same shape and add to the same groups
1277 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1278 AddToSameGroups( newElem, elem, aMesh );
1281 // Quadratic quadrangle
1283 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1285 // get surface elem is on
1286 int aShapeId = FindShape( elem );
1287 if ( aShapeId != helper.GetSubShapeID() ) {
1291 shape = aMesh->IndexToShape( aShapeId );
1292 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1293 TopoDS_Face face = TopoDS::Face( shape );
1294 surface = BRep_Tool::Surface( face );
1295 if ( !surface.IsNull() )
1296 helper.SetSubShape( shape );
1300 const SMDS_MeshNode* aNodes [8];
1301 const SMDS_MeshNode* inFaceNode = 0;
1302 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1304 while ( itN->more() ) {
1305 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1306 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1307 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1309 inFaceNode = aNodes[ i-1 ];
1313 // find middle point for (0,1,2,3)
1314 // and create a node in this point;
1316 if ( surface.IsNull() ) {
1318 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1322 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1325 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1327 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1329 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1330 myLastCreatedNodes.Append(newN);
1332 // create a new element
1333 const SMDS_MeshElement* newElem = 0;
1334 const SMDS_MeshNode* N[6];
1342 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1343 aNodes[6], aNodes[7], newN );
1352 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1353 aNodes[7], aNodes[4], newN );
1355 myLastCreatedElems.Append(newElem);
1356 aMesh->ChangeElementNodes( elem, N, 6 );
1357 // put a new triangle on the same shape and add to the same groups
1359 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1360 AddToSameGroups( newElem, elem, aMesh );
1367 //=======================================================================
1368 //function : getAngle
1370 //=======================================================================
1372 double getAngle(const SMDS_MeshElement * tr1,
1373 const SMDS_MeshElement * tr2,
1374 const SMDS_MeshNode * n1,
1375 const SMDS_MeshNode * n2)
1377 double angle = 2*PI; // bad angle
1380 SMESH::Controls::TSequenceOfXYZ P1, P2;
1381 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1382 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1385 if(!tr1->IsQuadratic())
1386 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1388 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1389 if ( N1.SquareMagnitude() <= gp::Resolution() )
1391 if(!tr2->IsQuadratic())
1392 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1394 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1395 if ( N2.SquareMagnitude() <= gp::Resolution() )
1398 // find the first diagonal node n1 in the triangles:
1399 // take in account a diagonal link orientation
1400 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1401 for ( int t = 0; t < 2; t++ ) {
1402 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1403 int i = 0, iDiag = -1;
1404 while ( it->more()) {
1405 const SMDS_MeshElement *n = it->next();
1406 if ( n == n1 || n == n2 )
1410 if ( i - iDiag == 1 )
1411 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1419 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1422 angle = N1.Angle( N2 );
1427 // =================================================
1428 // class generating a unique ID for a pair of nodes
1429 // and able to return nodes by that ID
1430 // =================================================
1434 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1435 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1438 long GetLinkID (const SMDS_MeshNode * n1,
1439 const SMDS_MeshNode * n2) const
1441 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1444 bool GetNodes (const long theLinkID,
1445 const SMDS_MeshNode* & theNode1,
1446 const SMDS_MeshNode* & theNode2) const
1448 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1449 if ( !theNode1 ) return false;
1450 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1451 if ( !theNode2 ) return false;
1457 const SMESHDS_Mesh* myMesh;
1462 //=======================================================================
1463 //function : TriToQuad
1464 //purpose : Fuse neighbour triangles into quadrangles.
1465 // theCrit is used to select a neighbour to fuse with.
1466 // theMaxAngle is a max angle between element normals at which
1467 // fusion is still performed.
1468 //=======================================================================
1470 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1471 SMESH::Controls::NumericalFunctorPtr theCrit,
1472 const double theMaxAngle)
1474 myLastCreatedElems.Clear();
1475 myLastCreatedNodes.Clear();
1477 MESSAGE( "::TriToQuad()" );
1479 if ( !theCrit.get() )
1482 SMESHDS_Mesh * aMesh = GetMeshDS();
1484 // Prepare data for algo: build
1485 // 1. map of elements with their linkIDs
1486 // 2. map of linkIDs with their elements
1488 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1489 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1490 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1491 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1493 TIDSortedElemSet::iterator itElem;
1494 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1495 const SMDS_MeshElement* elem = *itElem;
1496 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1497 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1498 if(!IsTria) continue;
1500 // retrieve element nodes
1501 const SMDS_MeshNode* aNodes [4];
1502 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1505 aNodes[ i++ ] = cast2Node( itN->next() );
1506 aNodes[ 3 ] = aNodes[ 0 ];
1509 for ( i = 0; i < 3; i++ ) {
1510 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1511 // check if elements sharing a link can be fused
1512 itLE = mapLi_listEl.find( link );
1513 if ( itLE != mapLi_listEl.end() ) {
1514 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1516 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1517 //if ( FindShape( elem ) != FindShape( elem2 ))
1518 // continue; // do not fuse triangles laying on different shapes
1519 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1520 continue; // avoid making badly shaped quads
1521 (*itLE).second.push_back( elem );
1524 mapLi_listEl[ link ].push_back( elem );
1526 mapEl_setLi [ elem ].insert( link );
1529 // Clean the maps from the links shared by a sole element, ie
1530 // links to which only one element is bound in mapLi_listEl
1532 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1533 int nbElems = (*itLE).second.size();
1534 if ( nbElems < 2 ) {
1535 const SMDS_MeshElement* elem = (*itLE).second.front();
1536 SMESH_TLink link = (*itLE).first;
1537 mapEl_setLi[ elem ].erase( link );
1538 if ( mapEl_setLi[ elem ].empty() )
1539 mapEl_setLi.erase( elem );
1543 // Algo: fuse triangles into quadrangles
1545 while ( ! mapEl_setLi.empty() ) {
1546 // Look for the start element:
1547 // the element having the least nb of shared links
1548 const SMDS_MeshElement* startElem = 0;
1550 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1551 int nbLinks = (*itEL).second.size();
1552 if ( nbLinks < minNbLinks ) {
1553 startElem = (*itEL).first;
1554 minNbLinks = nbLinks;
1555 if ( minNbLinks == 1 )
1560 // search elements to fuse starting from startElem or links of elements
1561 // fused earlyer - startLinks
1562 list< SMESH_TLink > startLinks;
1563 while ( startElem || !startLinks.empty() ) {
1564 while ( !startElem && !startLinks.empty() ) {
1565 // Get an element to start, by a link
1566 SMESH_TLink linkId = startLinks.front();
1567 startLinks.pop_front();
1568 itLE = mapLi_listEl.find( linkId );
1569 if ( itLE != mapLi_listEl.end() ) {
1570 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1571 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1572 for ( ; itE != listElem.end() ; itE++ )
1573 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1575 mapLi_listEl.erase( itLE );
1580 // Get candidates to be fused
1581 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1582 const SMESH_TLink *link12, *link13;
1584 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1585 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1586 ASSERT( !setLi.empty() );
1587 set< SMESH_TLink >::iterator itLi;
1588 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1590 const SMESH_TLink & link = (*itLi);
1591 itLE = mapLi_listEl.find( link );
1592 if ( itLE == mapLi_listEl.end() )
1595 const SMDS_MeshElement* elem = (*itLE).second.front();
1597 elem = (*itLE).second.back();
1598 mapLi_listEl.erase( itLE );
1599 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1610 // add other links of elem to list of links to re-start from
1611 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1612 set< SMESH_TLink >::iterator it;
1613 for ( it = links.begin(); it != links.end(); it++ ) {
1614 const SMESH_TLink& link2 = (*it);
1615 if ( link2 != link )
1616 startLinks.push_back( link2 );
1620 // Get nodes of possible quadrangles
1621 const SMDS_MeshNode *n12 [4], *n13 [4];
1622 bool Ok12 = false, Ok13 = false;
1623 const SMDS_MeshNode *linkNode1, *linkNode2;
1625 linkNode1 = link12->first;
1626 linkNode2 = link12->second;
1627 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1631 linkNode1 = link13->first;
1632 linkNode2 = link13->second;
1633 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1637 // Choose a pair to fuse
1638 if ( Ok12 && Ok13 ) {
1639 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1640 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1641 double aBadRate12 = getBadRate( &quad12, theCrit );
1642 double aBadRate13 = getBadRate( &quad13, theCrit );
1643 if ( aBadRate13 < aBadRate12 )
1650 // and remove fused elems and removed links from the maps
1651 mapEl_setLi.erase( tr1 );
1653 mapEl_setLi.erase( tr2 );
1654 mapLi_listEl.erase( *link12 );
1655 if(tr1->NbNodes()==3) {
1656 if( tr1->GetID() < tr2->GetID() ) {
1657 aMesh->ChangeElementNodes( tr1, n12, 4 );
1658 myLastCreatedElems.Append(tr1);
1659 aMesh->RemoveElement( tr2 );
1662 aMesh->ChangeElementNodes( tr2, n12, 4 );
1663 myLastCreatedElems.Append(tr2);
1664 aMesh->RemoveElement( tr1);
1668 const SMDS_MeshNode* N1 [6];
1669 const SMDS_MeshNode* N2 [6];
1670 GetNodesFromTwoTria(tr1,tr2,N1,N2);
1671 // now we receive following N1 and N2 (using numeration as above image)
1672 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1673 // i.e. first nodes from both arrays determ new diagonal
1674 const SMDS_MeshNode* aNodes[8];
1683 if( tr1->GetID() < tr2->GetID() ) {
1684 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1685 myLastCreatedElems.Append(tr1);
1686 GetMeshDS()->RemoveElement( tr2 );
1689 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1690 myLastCreatedElems.Append(tr2);
1691 GetMeshDS()->RemoveElement( tr1 );
1693 // remove middle node (9)
1694 GetMeshDS()->RemoveNode( N1[4] );
1698 mapEl_setLi.erase( tr3 );
1699 mapLi_listEl.erase( *link13 );
1700 if(tr1->NbNodes()==3) {
1701 if( tr1->GetID() < tr2->GetID() ) {
1702 aMesh->ChangeElementNodes( tr1, n13, 4 );
1703 myLastCreatedElems.Append(tr1);
1704 aMesh->RemoveElement( tr3 );
1707 aMesh->ChangeElementNodes( tr3, n13, 4 );
1708 myLastCreatedElems.Append(tr3);
1709 aMesh->RemoveElement( tr1 );
1713 const SMDS_MeshNode* N1 [6];
1714 const SMDS_MeshNode* N2 [6];
1715 GetNodesFromTwoTria(tr1,tr3,N1,N2);
1716 // now we receive following N1 and N2 (using numeration as above image)
1717 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1718 // i.e. first nodes from both arrays determ new diagonal
1719 const SMDS_MeshNode* aNodes[8];
1728 if( tr1->GetID() < tr2->GetID() ) {
1729 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1730 myLastCreatedElems.Append(tr1);
1731 GetMeshDS()->RemoveElement( tr3 );
1734 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1735 myLastCreatedElems.Append(tr3);
1736 GetMeshDS()->RemoveElement( tr1 );
1738 // remove middle node (9)
1739 GetMeshDS()->RemoveNode( N1[4] );
1743 // Next element to fuse: the rejected one
1745 startElem = Ok12 ? tr3 : tr2;
1747 } // if ( startElem )
1748 } // while ( startElem || !startLinks.empty() )
1749 } // while ( ! mapEl_setLi.empty() )
1755 /*#define DUMPSO(txt) \
1756 // cout << txt << endl;
1757 //=============================================================================
1761 //=============================================================================
1762 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1766 int tmp = idNodes[ i1 ];
1767 idNodes[ i1 ] = idNodes[ i2 ];
1768 idNodes[ i2 ] = tmp;
1769 gp_Pnt Ptmp = P[ i1 ];
1772 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1775 //=======================================================================
1776 //function : SortQuadNodes
1777 //purpose : Set 4 nodes of a quadrangle face in a good order.
1778 // Swap 1<->2 or 2<->3 nodes and correspondingly return
1780 //=======================================================================
1782 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1787 for ( i = 0; i < 4; i++ ) {
1788 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1790 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1793 gp_Vec V1(P[0], P[1]);
1794 gp_Vec V2(P[0], P[2]);
1795 gp_Vec V3(P[0], P[3]);
1797 gp_Vec Cross1 = V1 ^ V2;
1798 gp_Vec Cross2 = V2 ^ V3;
1801 if (Cross1.Dot(Cross2) < 0)
1806 if (Cross1.Dot(Cross2) < 0)
1810 swap ( i, i + 1, idNodes, P );
1812 // for ( int ii = 0; ii < 4; ii++ ) {
1813 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1814 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1820 //=======================================================================
1821 //function : SortHexaNodes
1822 //purpose : Set 8 nodes of a hexahedron in a good order.
1823 // Return success status
1824 //=======================================================================
1826 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1831 DUMPSO( "INPUT: ========================================");
1832 for ( i = 0; i < 8; i++ ) {
1833 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1834 if ( !n ) return false;
1835 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1836 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1838 DUMPSO( "========================================");
1841 set<int> faceNodes; // ids of bottom face nodes, to be found
1842 set<int> checkedId1; // ids of tried 2-nd nodes
1843 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1844 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
1845 int iMin, iLoop1 = 0;
1847 // Loop to try the 2-nd nodes
1849 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1851 // Find not checked 2-nd node
1852 for ( i = 1; i < 8; i++ )
1853 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1854 int id1 = idNodes[i];
1855 swap ( 1, i, idNodes, P );
1856 checkedId1.insert ( id1 );
1860 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1861 // ie that all but meybe one (id3 which is on the same face) nodes
1862 // lay on the same side from the triangle plane.
1864 bool manyInPlane = false; // more than 4 nodes lay in plane
1866 while ( ++iLoop2 < 6 ) {
1868 // get 1-2-3 plane coeffs
1869 Standard_Real A, B, C, D;
1870 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1871 if ( N.SquareMagnitude() > gp::Resolution() )
1873 gp_Pln pln ( P[0], N );
1874 pln.Coefficients( A, B, C, D );
1876 // find the node (iMin) closest to pln
1877 Standard_Real dist[ 8 ], minDist = DBL_MAX;
1879 for ( i = 3; i < 8; i++ ) {
1880 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1881 if ( fabs( dist[i] ) < minDist ) {
1882 minDist = fabs( dist[i] );
1885 if ( fabs( dist[i] ) <= tol )
1886 idInPln.insert( idNodes[i] );
1889 // there should not be more than 4 nodes in bottom plane
1890 if ( idInPln.size() > 1 )
1892 DUMPSO( "### idInPln.size() = " << idInPln.size());
1893 // idInPlane does not contain the first 3 nodes
1894 if ( manyInPlane || idInPln.size() == 5)
1895 return false; // all nodes in one plane
1898 // set the 1-st node to be not in plane
1899 for ( i = 3; i < 8; i++ ) {
1900 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1901 DUMPSO( "### Reset 0-th node");
1902 swap( 0, i, idNodes, P );
1907 // reset to re-check second nodes
1908 leastDist = DBL_MAX;
1912 break; // from iLoop2;
1915 // check that the other 4 nodes are on the same side
1916 bool sameSide = true;
1917 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1918 for ( i = 3; sameSide && i < 8; i++ ) {
1920 sameSide = ( isNeg == dist[i] <= 0.);
1923 // keep best solution
1924 if ( sameSide && minDist < leastDist ) {
1925 leastDist = minDist;
1927 faceNodes.insert( idNodes[ 1 ] );
1928 faceNodes.insert( idNodes[ 2 ] );
1929 faceNodes.insert( idNodes[ iMin ] );
1930 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1931 << " leastDist = " << leastDist);
1932 if ( leastDist <= DBL_MIN )
1937 // set next 3-d node to check
1938 int iNext = 2 + iLoop2;
1940 DUMPSO( "Try 2-nd");
1941 swap ( 2, iNext, idNodes, P );
1943 } // while ( iLoop2 < 6 )
1946 if ( faceNodes.empty() ) return false;
1948 // Put the faceNodes in proper places
1949 for ( i = 4; i < 8; i++ ) {
1950 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1951 // find a place to put
1953 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1955 DUMPSO( "Set faceNodes");
1956 swap ( iTo, i, idNodes, P );
1961 // Set nodes of the found bottom face in good order
1962 DUMPSO( " Found bottom face: ");
1963 i = SortQuadNodes( theMesh, idNodes );
1965 gp_Pnt Ptmp = P[ i ];
1970 // for ( int ii = 0; ii < 4; ii++ ) {
1971 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1972 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1975 // Gravity center of the top and bottom faces
1976 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1977 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1979 // Get direction from the bottom to the top face
1980 gp_Vec upDir ( aGCb, aGCt );
1981 Standard_Real upDirSize = upDir.Magnitude();
1982 if ( upDirSize <= gp::Resolution() ) return false;
1985 // Assure that the bottom face normal points up
1986 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1987 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1988 if ( Nb.Dot( upDir ) < 0 ) {
1989 DUMPSO( "Reverse bottom face");
1990 swap( 1, 3, idNodes, P );
1993 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1994 Standard_Real minDist = DBL_MAX;
1995 for ( i = 4; i < 8; i++ ) {
1996 // projection of P[i] to the plane defined by P[0] and upDir
1997 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1998 Standard_Real sqDist = P[0].SquareDistance( Pp );
1999 if ( sqDist < minDist ) {
2004 DUMPSO( "Set 4-th");
2005 swap ( 4, iMin, idNodes, P );
2007 // Set nodes of the top face in good order
2008 DUMPSO( "Sort top face");
2009 i = SortQuadNodes( theMesh, &idNodes[4] );
2012 gp_Pnt Ptmp = P[ i ];
2017 // Assure that direction of the top face normal is from the bottom face
2018 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2019 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2020 if ( Nt.Dot( upDir ) < 0 ) {
2021 DUMPSO( "Reverse top face");
2022 swap( 5, 7, idNodes, P );
2025 // DUMPSO( "OUTPUT: ========================================");
2026 // for ( i = 0; i < 8; i++ ) {
2027 // float *p = ugrid->GetPoint(idNodes[i]);
2028 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2034 //================================================================================
2036 * \brief Return nodes linked to the given one
2037 * \param theNode - the node
2038 * \param linkedNodes - the found nodes
2039 * \param type - the type of elements to check
2041 * Medium nodes are ignored
2043 //================================================================================
2045 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2046 TIDSortedElemSet & linkedNodes,
2047 SMDSAbs_ElementType type )
2049 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2050 while ( elemIt->more() )
2052 const SMDS_MeshElement* elem = elemIt->next();
2053 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2054 if ( elem->GetType() == SMDSAbs_Volume )
2056 SMDS_VolumeTool vol( elem );
2057 while ( nodeIt->more() ) {
2058 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2059 if ( theNode != n && vol.IsLinked( theNode, n ))
2060 linkedNodes.insert( n );
2065 for ( int i = 0; nodeIt->more(); ++i ) {
2066 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2067 if ( n == theNode ) {
2068 int iBefore = i - 1;
2070 if ( elem->IsQuadratic() ) {
2071 int nb = elem->NbNodes() / 2;
2072 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2073 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2075 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2076 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2083 //=======================================================================
2084 //function : laplacianSmooth
2085 //purpose : pulls theNode toward the center of surrounding nodes directly
2086 // connected to that node along an element edge
2087 //=======================================================================
2089 void laplacianSmooth(const SMDS_MeshNode* theNode,
2090 const Handle(Geom_Surface)& theSurface,
2091 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2093 // find surrounding nodes
2095 TIDSortedElemSet nodeSet;
2096 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2098 // compute new coodrs
2100 double coord[] = { 0., 0., 0. };
2101 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2102 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2103 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2104 if ( theSurface.IsNull() ) { // smooth in 3D
2105 coord[0] += node->X();
2106 coord[1] += node->Y();
2107 coord[2] += node->Z();
2109 else { // smooth in 2D
2110 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2111 gp_XY* uv = theUVMap[ node ];
2112 coord[0] += uv->X();
2113 coord[1] += uv->Y();
2116 int nbNodes = nodeSet.size();
2119 coord[0] /= nbNodes;
2120 coord[1] /= nbNodes;
2122 if ( !theSurface.IsNull() ) {
2123 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2124 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2125 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2131 coord[2] /= nbNodes;
2135 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2138 //=======================================================================
2139 //function : centroidalSmooth
2140 //purpose : pulls theNode toward the element-area-weighted centroid of the
2141 // surrounding elements
2142 //=======================================================================
2144 void centroidalSmooth(const SMDS_MeshNode* theNode,
2145 const Handle(Geom_Surface)& theSurface,
2146 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2148 gp_XYZ aNewXYZ(0.,0.,0.);
2149 SMESH::Controls::Area anAreaFunc;
2150 double totalArea = 0.;
2155 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2156 while ( elemIt->more() )
2158 const SMDS_MeshElement* elem = elemIt->next();
2161 gp_XYZ elemCenter(0.,0.,0.);
2162 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2163 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2164 int nn = elem->NbNodes();
2165 if(elem->IsQuadratic()) nn = nn/2;
2167 //while ( itN->more() ) {
2169 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2171 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2172 aNodePoints.push_back( aP );
2173 if ( !theSurface.IsNull() ) { // smooth in 2D
2174 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2175 gp_XY* uv = theUVMap[ aNode ];
2176 aP.SetCoord( uv->X(), uv->Y(), 0. );
2180 double elemArea = anAreaFunc.GetValue( aNodePoints );
2181 totalArea += elemArea;
2183 aNewXYZ += elemCenter * elemArea;
2185 aNewXYZ /= totalArea;
2186 if ( !theSurface.IsNull() ) {
2187 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2188 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2193 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2196 //=======================================================================
2197 //function : getClosestUV
2198 //purpose : return UV of closest projection
2199 //=======================================================================
2201 static bool getClosestUV (Extrema_GenExtPS& projector,
2202 const gp_Pnt& point,
2205 projector.Perform( point );
2206 if ( projector.IsDone() ) {
2207 double u, v, minVal = DBL_MAX;
2208 for ( int i = projector.NbExt(); i > 0; i-- )
2209 if ( projector.Value( i ) < minVal ) {
2210 minVal = projector.Value( i );
2211 projector.Point( i ).Parameter( u, v );
2213 result.SetCoord( u, v );
2219 //=======================================================================
2221 //purpose : Smooth theElements during theNbIterations or until a worst
2222 // element has aspect ratio <= theTgtAspectRatio.
2223 // Aspect Ratio varies in range [1.0, inf].
2224 // If theElements is empty, the whole mesh is smoothed.
2225 // theFixedNodes contains additionally fixed nodes. Nodes built
2226 // on edges and boundary nodes are always fixed.
2227 //=======================================================================
2229 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2230 set<const SMDS_MeshNode*> & theFixedNodes,
2231 const SmoothMethod theSmoothMethod,
2232 const int theNbIterations,
2233 double theTgtAspectRatio,
2236 myLastCreatedElems.Clear();
2237 myLastCreatedNodes.Clear();
2239 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2241 if ( theTgtAspectRatio < 1.0 )
2242 theTgtAspectRatio = 1.0;
2244 const double disttol = 1.e-16;
2246 SMESH::Controls::AspectRatio aQualityFunc;
2248 SMESHDS_Mesh* aMesh = GetMeshDS();
2250 if ( theElems.empty() ) {
2251 // add all faces to theElems
2252 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2253 while ( fIt->more() ) {
2254 const SMDS_MeshElement* face = fIt->next();
2255 theElems.insert( face );
2258 // get all face ids theElems are on
2259 set< int > faceIdSet;
2260 TIDSortedElemSet::iterator itElem;
2262 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2263 int fId = FindShape( *itElem );
2264 // check that corresponding submesh exists and a shape is face
2266 faceIdSet.find( fId ) == faceIdSet.end() &&
2267 aMesh->MeshElements( fId )) {
2268 TopoDS_Shape F = aMesh->IndexToShape( fId );
2269 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2270 faceIdSet.insert( fId );
2273 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2275 // ===============================================
2276 // smooth elements on each TopoDS_Face separately
2277 // ===============================================
2279 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2280 for ( ; fId != faceIdSet.rend(); ++fId ) {
2281 // get face surface and submesh
2282 Handle(Geom_Surface) surface;
2283 SMESHDS_SubMesh* faceSubMesh = 0;
2285 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2286 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2287 bool isUPeriodic = false, isVPeriodic = false;
2289 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2290 surface = BRep_Tool::Surface( face );
2291 faceSubMesh = aMesh->MeshElements( *fId );
2292 fToler2 = BRep_Tool::Tolerance( face );
2293 fToler2 *= fToler2 * 10.;
2294 isUPeriodic = surface->IsUPeriodic();
2296 vPeriod = surface->UPeriod();
2297 isVPeriodic = surface->IsVPeriodic();
2299 uPeriod = surface->VPeriod();
2300 surface->Bounds( u1, u2, v1, v2 );
2302 // ---------------------------------------------------------
2303 // for elements on a face, find movable and fixed nodes and
2304 // compute UV for them
2305 // ---------------------------------------------------------
2306 bool checkBoundaryNodes = false;
2307 bool isQuadratic = false;
2308 set<const SMDS_MeshNode*> setMovableNodes;
2309 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2310 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2311 list< const SMDS_MeshElement* > elemsOnFace;
2313 Extrema_GenExtPS projector;
2314 GeomAdaptor_Surface surfAdaptor;
2315 if ( !surface.IsNull() ) {
2316 surfAdaptor.Load( surface );
2317 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2319 int nbElemOnFace = 0;
2320 itElem = theElems.begin();
2321 // loop on not yet smoothed elements: look for elems on a face
2322 while ( itElem != theElems.end() ) {
2323 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2324 break; // all elements found
2326 const SMDS_MeshElement* elem = *itElem;
2327 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2328 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2332 elemsOnFace.push_back( elem );
2333 theElems.erase( itElem++ );
2337 isQuadratic = elem->IsQuadratic();
2339 // get movable nodes of elem
2340 const SMDS_MeshNode* node;
2341 SMDS_TypeOfPosition posType;
2342 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2343 int nn = 0, nbn = elem->NbNodes();
2344 if(elem->IsQuadratic())
2346 while ( nn++ < nbn ) {
2347 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2348 const SMDS_PositionPtr& pos = node->GetPosition();
2349 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2350 if (posType != SMDS_TOP_EDGE &&
2351 posType != SMDS_TOP_VERTEX &&
2352 theFixedNodes.find( node ) == theFixedNodes.end())
2354 // check if all faces around the node are on faceSubMesh
2355 // because a node on edge may be bound to face
2356 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2358 if ( faceSubMesh ) {
2359 while ( eIt->more() && all ) {
2360 const SMDS_MeshElement* e = eIt->next();
2361 all = faceSubMesh->Contains( e );
2365 setMovableNodes.insert( node );
2367 checkBoundaryNodes = true;
2369 if ( posType == SMDS_TOP_3DSPACE )
2370 checkBoundaryNodes = true;
2373 if ( surface.IsNull() )
2376 // get nodes to check UV
2377 list< const SMDS_MeshNode* > uvCheckNodes;
2378 itN = elem->nodesIterator();
2379 nn = 0; nbn = elem->NbNodes();
2380 if(elem->IsQuadratic())
2382 while ( nn++ < nbn ) {
2383 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2384 if ( uvMap.find( node ) == uvMap.end() )
2385 uvCheckNodes.push_back( node );
2386 // add nodes of elems sharing node
2387 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2388 // while ( eIt->more() ) {
2389 // const SMDS_MeshElement* e = eIt->next();
2390 // if ( e != elem ) {
2391 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2392 // while ( nIt->more() ) {
2393 // const SMDS_MeshNode* n =
2394 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2395 // if ( uvMap.find( n ) == uvMap.end() )
2396 // uvCheckNodes.push_back( n );
2402 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2403 for ( ; n != uvCheckNodes.end(); ++n ) {
2406 const SMDS_PositionPtr& pos = node->GetPosition();
2407 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2409 switch ( posType ) {
2410 case SMDS_TOP_FACE: {
2411 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2412 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2415 case SMDS_TOP_EDGE: {
2416 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2417 Handle(Geom2d_Curve) pcurve;
2418 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2419 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2420 if ( !pcurve.IsNull() ) {
2421 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2422 uv = pcurve->Value( u ).XY();
2426 case SMDS_TOP_VERTEX: {
2427 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2428 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2429 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2434 // check existing UV
2435 bool project = true;
2436 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2437 double dist1 = DBL_MAX, dist2 = 0;
2438 if ( posType != SMDS_TOP_3DSPACE ) {
2439 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2440 project = dist1 > fToler2;
2442 if ( project ) { // compute new UV
2444 if ( !getClosestUV( projector, pNode, newUV )) {
2445 MESSAGE("Node Projection Failed " << node);
2449 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2451 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2453 if ( posType != SMDS_TOP_3DSPACE )
2454 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2455 if ( dist2 < dist1 )
2459 // store UV in the map
2460 listUV.push_back( uv );
2461 uvMap.insert( make_pair( node, &listUV.back() ));
2463 } // loop on not yet smoothed elements
2465 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2466 checkBoundaryNodes = true;
2468 // fix nodes on mesh boundary
2470 if ( checkBoundaryNodes ) {
2471 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2472 map< NLink, int >::iterator link_nb;
2473 // put all elements links to linkNbMap
2474 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2475 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2476 const SMDS_MeshElement* elem = (*elemIt);
2477 int nbn = elem->NbNodes();
2478 if(elem->IsQuadratic())
2480 // loop on elem links: insert them in linkNbMap
2481 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2482 for ( int iN = 0; iN < nbn; ++iN ) {
2483 curNode = elem->GetNode( iN );
2485 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2486 else link = make_pair( prevNode , curNode );
2488 link_nb = linkNbMap.find( link );
2489 if ( link_nb == linkNbMap.end() )
2490 linkNbMap.insert( make_pair ( link, 1 ));
2495 // remove nodes that are in links encountered only once from setMovableNodes
2496 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2497 if ( link_nb->second == 1 ) {
2498 setMovableNodes.erase( link_nb->first.first );
2499 setMovableNodes.erase( link_nb->first.second );
2504 // -----------------------------------------------------
2505 // for nodes on seam edge, compute one more UV ( uvMap2 );
2506 // find movable nodes linked to nodes on seam and which
2507 // are to be smoothed using the second UV ( uvMap2 )
2508 // -----------------------------------------------------
2510 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2511 if ( !surface.IsNull() ) {
2512 TopExp_Explorer eExp( face, TopAbs_EDGE );
2513 for ( ; eExp.More(); eExp.Next() ) {
2514 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2515 if ( !BRep_Tool::IsClosed( edge, face ))
2517 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2518 if ( !sm ) continue;
2519 // find out which parameter varies for a node on seam
2522 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2523 if ( pcurve.IsNull() ) continue;
2524 uv1 = pcurve->Value( f );
2526 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2527 if ( pcurve.IsNull() ) continue;
2528 uv2 = pcurve->Value( f );
2529 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2531 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2532 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2534 // get nodes on seam and its vertices
2535 list< const SMDS_MeshNode* > seamNodes;
2536 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2537 while ( nSeamIt->more() ) {
2538 const SMDS_MeshNode* node = nSeamIt->next();
2539 if ( !isQuadratic || !IsMedium( node ))
2540 seamNodes.push_back( node );
2542 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2543 for ( ; vExp.More(); vExp.Next() ) {
2544 sm = aMesh->MeshElements( vExp.Current() );
2546 nSeamIt = sm->GetNodes();
2547 while ( nSeamIt->more() )
2548 seamNodes.push_back( nSeamIt->next() );
2551 // loop on nodes on seam
2552 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2553 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2554 const SMDS_MeshNode* nSeam = *noSeIt;
2555 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2556 if ( n_uv == uvMap.end() )
2559 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2560 // set the second UV
2561 listUV.push_back( *n_uv->second );
2562 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2563 if ( uvMap2.empty() )
2564 uvMap2 = uvMap; // copy the uvMap contents
2565 uvMap2[ nSeam ] = &listUV.back();
2567 // collect movable nodes linked to ones on seam in nodesNearSeam
2568 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2569 while ( eIt->more() ) {
2570 const SMDS_MeshElement* e = eIt->next();
2571 int nbUseMap1 = 0, nbUseMap2 = 0;
2572 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2573 int nn = 0, nbn = e->NbNodes();
2574 if(e->IsQuadratic()) nbn = nbn/2;
2575 while ( nn++ < nbn )
2577 const SMDS_MeshNode* n =
2578 static_cast<const SMDS_MeshNode*>( nIt->next() );
2580 setMovableNodes.find( n ) == setMovableNodes.end() )
2582 // add only nodes being closer to uv2 than to uv1
2583 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2584 0.5 * ( n->Y() + nSeam->Y() ),
2585 0.5 * ( n->Z() + nSeam->Z() ));
2587 getClosestUV( projector, pMid, uv );
2588 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2589 nodesNearSeam.insert( n );
2595 // for centroidalSmooth all element nodes must
2596 // be on one side of a seam
2597 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2598 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2600 while ( nn++ < nbn ) {
2601 const SMDS_MeshNode* n =
2602 static_cast<const SMDS_MeshNode*>( nIt->next() );
2603 setMovableNodes.erase( n );
2607 } // loop on nodes on seam
2608 } // loop on edge of a face
2609 } // if ( !face.IsNull() )
2611 if ( setMovableNodes.empty() ) {
2612 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2613 continue; // goto next face
2621 double maxRatio = -1., maxDisplacement = -1.;
2622 set<const SMDS_MeshNode*>::iterator nodeToMove;
2623 for ( it = 0; it < theNbIterations; it++ ) {
2624 maxDisplacement = 0.;
2625 nodeToMove = setMovableNodes.begin();
2626 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2627 const SMDS_MeshNode* node = (*nodeToMove);
2628 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2631 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2632 if ( theSmoothMethod == LAPLACIAN )
2633 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2635 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2637 // node displacement
2638 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2639 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2640 if ( aDispl > maxDisplacement )
2641 maxDisplacement = aDispl;
2643 // no node movement => exit
2644 //if ( maxDisplacement < 1.e-16 ) {
2645 if ( maxDisplacement < disttol ) {
2646 MESSAGE("-- no node movement --");
2650 // check elements quality
2652 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2653 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2654 const SMDS_MeshElement* elem = (*elemIt);
2655 if ( !elem || elem->GetType() != SMDSAbs_Face )
2657 SMESH::Controls::TSequenceOfXYZ aPoints;
2658 if ( aQualityFunc.GetPoints( elem, aPoints )) {
2659 double aValue = aQualityFunc.GetValue( aPoints );
2660 if ( aValue > maxRatio )
2664 if ( maxRatio <= theTgtAspectRatio ) {
2665 MESSAGE("-- quality achived --");
2668 if (it+1 == theNbIterations) {
2669 MESSAGE("-- Iteration limit exceeded --");
2671 } // smoothing iterations
2673 MESSAGE(" Face id: " << *fId <<
2674 " Nb iterstions: " << it <<
2675 " Displacement: " << maxDisplacement <<
2676 " Aspect Ratio " << maxRatio);
2678 // ---------------------------------------
2679 // new nodes positions are computed,
2680 // record movement in DS and set new UV
2681 // ---------------------------------------
2682 nodeToMove = setMovableNodes.begin();
2683 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2684 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2685 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2686 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2687 if ( node_uv != uvMap.end() ) {
2688 gp_XY* uv = node_uv->second;
2690 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2694 // move medium nodes of quadratic elements
2697 SMESH_MesherHelper helper( *GetMesh() );
2698 if ( !face.IsNull() )
2699 helper.SetSubShape( face );
2700 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2701 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2702 const SMDS_QuadraticFaceOfNodes* QF =
2703 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2705 vector<const SMDS_MeshNode*> Ns;
2706 Ns.reserve(QF->NbNodes()+1);
2707 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2708 while ( anIter->more() )
2709 Ns.push_back( anIter->next() );
2710 Ns.push_back( Ns[0] );
2712 for(int i=0; i<QF->NbNodes(); i=i+2) {
2713 if ( !surface.IsNull() ) {
2714 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2715 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2716 gp_XY uv = ( uv1 + uv2 ) / 2.;
2717 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2718 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2721 x = (Ns[i]->X() + Ns[i+2]->X())/2;
2722 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2723 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2725 if( fabs( Ns[i+1]->X() - x ) > disttol ||
2726 fabs( Ns[i+1]->Y() - y ) > disttol ||
2727 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2728 // we have to move i+1 node
2729 aMesh->MoveNode( Ns[i+1], x, y, z );
2736 } // loop on face ids
2740 //=======================================================================
2741 //function : isReverse
2742 //purpose : Return true if normal of prevNodes is not co-directied with
2743 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2744 // iNotSame is where prevNodes and nextNodes are different
2745 //=======================================================================
2747 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2748 vector<const SMDS_MeshNode*> nextNodes,
2752 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2753 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2755 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2756 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2757 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2758 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2760 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2761 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2762 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2763 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2765 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2767 return (vA ^ vB) * vN < 0.0;
2770 //=======================================================================
2772 * \brief Create elements by sweeping an element
2773 * \param elem - element to sweep
2774 * \param newNodesItVec - nodes generated from each node of the element
2775 * \param newElems - generated elements
2776 * \param nbSteps - number of sweeping steps
2777 * \param srcElements - to append elem for each generated element
2779 //=======================================================================
2781 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
2782 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2783 list<const SMDS_MeshElement*>& newElems,
2785 SMESH_SequenceOfElemPtr& srcElements)
2787 SMESHDS_Mesh* aMesh = GetMeshDS();
2789 // Loop on elem nodes:
2790 // find new nodes and detect same nodes indices
2791 int nbNodes = elem->NbNodes();
2792 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2793 vector<const SMDS_MeshNode*> prevNod( nbNodes );
2794 vector<const SMDS_MeshNode*> nextNod( nbNodes );
2795 vector<const SMDS_MeshNode*> midlNod( nbNodes );
2797 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2798 vector<int> sames(nbNodes);
2799 vector<bool> issimple(nbNodes);
2801 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2802 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2803 const SMDS_MeshNode* node = nnIt->first;
2804 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2805 if ( listNewNodes.empty() ) {
2809 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
2811 itNN[ iNode ] = listNewNodes.begin();
2812 prevNod[ iNode ] = node;
2813 nextNod[ iNode ] = listNewNodes.front();
2814 if( !elem->IsQuadratic() || !issimple[iNode] ) {
2815 if ( prevNod[ iNode ] != nextNod [ iNode ])
2816 iNotSameNode = iNode;
2820 sames[nbSame++] = iNode;
2825 //cout<<" nbSame = "<<nbSame<<endl;
2826 if ( nbSame == nbNodes || nbSame > 2) {
2827 MESSAGE( " Too many same nodes of element " << elem->GetID() );
2828 //INFOS( " Too many same nodes of element " << elem->GetID() );
2832 // if( elem->IsQuadratic() && nbSame>0 ) {
2833 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2837 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2838 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2840 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2841 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2842 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2846 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2847 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2848 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2849 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2851 // check element orientation
2853 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2854 //MESSAGE("Reversed elem " << elem );
2858 std::swap( iBeforeSame, iAfterSame );
2861 // make new elements
2862 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
2864 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2865 if(issimple[iNode]) {
2866 nextNod[ iNode ] = *itNN[ iNode ];
2870 if( elem->GetType()==SMDSAbs_Node ) {
2871 // we have to use two nodes
2872 midlNod[ iNode ] = *itNN[ iNode ];
2874 nextNod[ iNode ] = *itNN[ iNode ];
2877 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
2878 // we have to use each second node
2880 nextNod[ iNode ] = *itNN[ iNode ];
2884 // we have to use two nodes
2885 midlNod[ iNode ] = *itNN[ iNode ];
2887 nextNod[ iNode ] = *itNN[ iNode ];
2892 SMDS_MeshElement* aNewElem = 0;
2893 if(!elem->IsPoly()) {
2894 switch ( nbNodes ) {
2898 if ( nbSame == 0 ) {
2900 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2902 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2908 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2909 nextNod[ 1 ], nextNod[ 0 ] );
2911 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2912 nextNod[ iNotSameNode ] );
2916 case 3: { // TRIANGLE or quadratic edge
2917 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2919 if ( nbSame == 0 ) // --- pentahedron
2920 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2921 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2923 else if ( nbSame == 1 ) // --- pyramid
2924 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2925 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2926 nextNod[ iSameNode ]);
2928 else // 2 same nodes: --- tetrahedron
2929 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2930 nextNod[ iNotSameNode ]);
2932 else { // quadratic edge
2933 if(nbSame==0) { // quadratic quadrangle
2934 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2935 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2937 else if(nbSame==1) { // quadratic triangle
2939 return; // medium node on axis
2941 else if(sames[0]==0) {
2942 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2943 nextNod[2], midlNod[1], prevNod[2]);
2945 else { // sames[0]==1
2946 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2947 midlNod[0], nextNod[2], prevNod[2]);
2956 case 4: { // QUADRANGLE
2958 if ( nbSame == 0 ) // --- hexahedron
2959 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2960 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2962 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2963 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2964 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2965 nextNod[ iSameNode ]);
2966 newElems.push_back( aNewElem );
2967 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2968 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
2969 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
2971 else if ( nbSame == 2 ) { // pentahedron
2972 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2973 // iBeforeSame is same too
2974 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2975 nextNod[ iOpposSame ], prevNod[ iSameNode ],
2976 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
2978 // iAfterSame is same too
2979 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2980 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2981 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
2985 case 6: { // quadratic triangle
2986 // create pentahedron with 15 nodes
2988 if(i0>0) { // reversed case
2989 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2990 nextNod[0], nextNod[2], nextNod[1],
2991 prevNod[5], prevNod[4], prevNod[3],
2992 nextNod[5], nextNod[4], nextNod[3],
2993 midlNod[0], midlNod[2], midlNod[1]);
2995 else { // not reversed case
2996 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2997 nextNod[0], nextNod[1], nextNod[2],
2998 prevNod[3], prevNod[4], prevNod[5],
2999 nextNod[3], nextNod[4], nextNod[5],
3000 midlNod[0], midlNod[1], midlNod[2]);
3003 else if(nbSame==1) {
3004 // 2d order pyramid of 13 nodes
3005 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3006 // int n12,int n23,int n34,int n41,
3007 // int n15,int n25,int n35,int n45, int ID);
3009 int n1,n4,n41,n15,n45;
3010 if(i0>0) { // reversed case
3011 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3012 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3018 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3019 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3024 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3025 nextNod[n4], prevNod[n4], prevNod[n5],
3026 midlNod[n1], nextNod[n41],
3027 midlNod[n4], prevNod[n41],
3028 prevNod[n15], nextNod[n15],
3029 nextNod[n45], prevNod[n45]);
3031 else if(nbSame==2) {
3032 // 2d order tetrahedron of 10 nodes
3033 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3034 // int n12,int n23,int n31,
3035 // int n14,int n24,int n34, int ID);
3036 int n1 = iNotSameNode;
3037 int n2,n3,n12,n23,n31;
3038 if(i0>0) { // reversed case
3039 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3040 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3046 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3047 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3052 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3053 prevNod[n12], prevNod[n23], prevNod[n31],
3054 midlNod[n1], nextNod[n12], nextNod[n31]);
3058 case 8: { // quadratic quadrangle
3060 // create hexahedron with 20 nodes
3061 if(i0>0) { // reversed case
3062 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3063 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3064 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3065 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3066 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3068 else { // not reversed case
3069 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3070 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3071 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3072 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3073 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3076 else if(nbSame==1) {
3077 // --- pyramid + pentahedron - can not be created since it is needed
3078 // additional middle node ot the center of face
3079 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3082 else if(nbSame==2) {
3083 // 2d order Pentahedron with 15 nodes
3084 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3085 // int n12,int n23,int n31,int n45,int n56,int n64,
3086 // int n14,int n25,int n36, int ID);
3088 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3089 // iBeforeSame is same too
3096 // iAfterSame is same too
3102 int n12,n45,n14,n25;
3103 if(i0>0) { //reversed case
3115 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3116 prevNod[n4], prevNod[n5], nextNod[n5],
3117 prevNod[n12], midlNod[n2], nextNod[n12],
3118 prevNod[n45], midlNod[n5], nextNod[n45],
3119 prevNod[n14], prevNod[n25], nextNod[n25]);
3124 // realized for extrusion only
3125 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3126 //vector<int> quantities (nbNodes + 2);
3128 //quantities[0] = nbNodes; // bottom of prism
3129 //for (int inode = 0; inode < nbNodes; inode++) {
3130 // polyedre_nodes[inode] = prevNod[inode];
3133 //quantities[1] = nbNodes; // top of prism
3134 //for (int inode = 0; inode < nbNodes; inode++) {
3135 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3138 //for (int iface = 0; iface < nbNodes; iface++) {
3139 // quantities[iface + 2] = 4;
3140 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3141 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3142 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3143 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3144 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3146 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3153 // realized for extrusion only
3154 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3155 vector<int> quantities (nbNodes + 2);
3157 quantities[0] = nbNodes; // bottom of prism
3158 for (int inode = 0; inode < nbNodes; inode++) {
3159 polyedre_nodes[inode] = prevNod[inode];
3162 quantities[1] = nbNodes; // top of prism
3163 for (int inode = 0; inode < nbNodes; inode++) {
3164 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3167 for (int iface = 0; iface < nbNodes; iface++) {
3168 quantities[iface + 2] = 4;
3169 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3170 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3171 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3172 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3173 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3175 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3179 newElems.push_back( aNewElem );
3180 myLastCreatedElems.Append(aNewElem);
3181 srcElements.Append( elem );
3184 // set new prev nodes
3185 for ( iNode = 0; iNode < nbNodes; iNode++ )
3186 prevNod[ iNode ] = nextNod[ iNode ];
3191 //=======================================================================
3193 * \brief Create 1D and 2D elements around swept elements
3194 * \param mapNewNodes - source nodes and ones generated from them
3195 * \param newElemsMap - source elements and ones generated from them
3196 * \param elemNewNodesMap - nodes generated from each node of each element
3197 * \param elemSet - all swept elements
3198 * \param nbSteps - number of sweeping steps
3199 * \param srcElements - to append elem for each generated element
3201 //=======================================================================
3203 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3204 TElemOfElemListMap & newElemsMap,
3205 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3206 TIDSortedElemSet& elemSet,
3208 SMESH_SequenceOfElemPtr& srcElements)
3210 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3211 SMESHDS_Mesh* aMesh = GetMeshDS();
3213 // Find nodes belonging to only one initial element - sweep them to get edges.
3215 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3216 for ( ; nList != mapNewNodes.end(); nList++ ) {
3217 const SMDS_MeshNode* node =
3218 static_cast<const SMDS_MeshNode*>( nList->first );
3219 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3220 int nbInitElems = 0;
3221 const SMDS_MeshElement* el = 0;
3222 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3223 while ( eIt->more() && nbInitElems < 2 ) {
3225 SMDSAbs_ElementType type = el->GetType();
3226 if ( type == SMDSAbs_Volume || type < highType ) continue;
3227 if ( type > highType ) {
3231 if ( elemSet.find(el) != elemSet.end() )
3234 if ( nbInitElems < 2 ) {
3235 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3236 if(!NotCreateEdge) {
3237 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3238 list<const SMDS_MeshElement*> newEdges;
3239 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3244 // Make a ceiling for each element ie an equal element of last new nodes.
3245 // Find free links of faces - make edges and sweep them into faces.
3247 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3248 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3249 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3250 const SMDS_MeshElement* elem = itElem->first;
3251 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3253 if ( elem->GetType() == SMDSAbs_Edge ) {
3254 // create a ceiling edge
3255 if (!elem->IsQuadratic()) {
3256 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3257 vecNewNodes[ 1 ]->second.back())) {
3258 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3259 vecNewNodes[ 1 ]->second.back()));
3260 srcElements.Append( myLastCreatedElems.Last() );
3264 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3265 vecNewNodes[ 1 ]->second.back(),
3266 vecNewNodes[ 2 ]->second.back())) {
3267 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3268 vecNewNodes[ 1 ]->second.back(),
3269 vecNewNodes[ 2 ]->second.back()));
3270 srcElements.Append( myLastCreatedElems.Last() );
3274 if ( elem->GetType() != SMDSAbs_Face )
3277 if(itElem->second.size()==0) continue;
3279 bool hasFreeLinks = false;
3281 TIDSortedElemSet avoidSet;
3282 avoidSet.insert( elem );
3284 set<const SMDS_MeshNode*> aFaceLastNodes;
3285 int iNode, nbNodes = vecNewNodes.size();
3286 if(!elem->IsQuadratic()) {
3287 // loop on the face nodes
3288 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3289 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3290 // look for free links of the face
3291 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3292 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3293 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3294 // check if a link is free
3295 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3296 hasFreeLinks = true;
3297 // make an edge and a ceiling for a new edge
3298 if ( !aMesh->FindEdge( n1, n2 )) {
3299 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3300 srcElements.Append( myLastCreatedElems.Last() );
3302 n1 = vecNewNodes[ iNode ]->second.back();
3303 n2 = vecNewNodes[ iNext ]->second.back();
3304 if ( !aMesh->FindEdge( n1, n2 )) {
3305 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3306 srcElements.Append( myLastCreatedElems.Last() );
3311 else { // elem is quadratic face
3312 int nbn = nbNodes/2;
3313 for ( iNode = 0; iNode < nbn; iNode++ ) {
3314 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3315 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3316 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3317 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3318 // check if a link is free
3319 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3320 hasFreeLinks = true;
3321 // make an edge and a ceiling for a new edge
3323 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3324 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3325 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3326 srcElements.Append( myLastCreatedElems.Last() );
3328 n1 = vecNewNodes[ iNode ]->second.back();
3329 n2 = vecNewNodes[ iNext ]->second.back();
3330 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3331 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3332 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3333 srcElements.Append( myLastCreatedElems.Last() );
3337 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3338 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3342 // sweep free links into faces
3344 if ( hasFreeLinks ) {
3345 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3346 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3348 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3349 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3350 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3351 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3353 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3354 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3356 while ( iVol++ < volNb ) v++;
3357 // find indices of free faces of a volume and their source edges
3358 list< int > freeInd;
3359 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3360 SMDS_VolumeTool vTool( *v );
3361 int iF, nbF = vTool.NbFaces();
3362 for ( iF = 0; iF < nbF; iF ++ ) {
3363 if (vTool.IsFreeFace( iF ) &&
3364 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3365 initNodeSet != faceNodeSet) // except an initial face
3367 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3369 freeInd.push_back( iF );
3370 // find source edge of a free face iF
3371 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3372 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3373 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3374 initNodeSet.begin(), initNodeSet.end(),
3375 commonNodes.begin());
3376 if ( (*v)->IsQuadratic() )
3377 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3379 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3381 if ( !srcEdges.back() )
3383 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3384 << iF << " of volume #" << vTool.ID() << endl;
3389 if ( freeInd.empty() )
3392 // create faces for all steps;
3393 // if such a face has been already created by sweep of edge,
3394 // assure that its orientation is OK
3395 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3397 vTool.SetExternalNormal();
3398 list< int >::iterator ind = freeInd.begin();
3399 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3400 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3402 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3403 int nbn = vTool.NbFaceNodes( *ind );
3405 case 3: { ///// triangle
3406 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3408 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3409 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3410 aMesh->ChangeElementNodes( f, nodes, nbn );
3413 case 4: { ///// quadrangle
3414 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3416 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3417 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3418 aMesh->ChangeElementNodes( f, nodes, nbn );
3422 if( (*v)->IsQuadratic() ) {
3423 if(nbn==6) { /////// quadratic triangle
3424 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3425 nodes[1], nodes[3], nodes[5] );
3427 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3428 nodes[1], nodes[3], nodes[5]));
3430 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3431 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3432 tmpnodes[0] = nodes[0];
3433 tmpnodes[1] = nodes[2];
3434 tmpnodes[2] = nodes[4];
3435 tmpnodes[3] = nodes[1];
3436 tmpnodes[4] = nodes[3];
3437 tmpnodes[5] = nodes[5];
3438 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3441 else { /////// quadratic quadrangle
3442 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3443 nodes[1], nodes[3], nodes[5], nodes[7] );
3445 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3446 nodes[1], nodes[3], nodes[5], nodes[7]));
3448 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3449 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3450 tmpnodes[0] = nodes[0];
3451 tmpnodes[1] = nodes[2];
3452 tmpnodes[2] = nodes[4];
3453 tmpnodes[3] = nodes[6];
3454 tmpnodes[4] = nodes[1];
3455 tmpnodes[5] = nodes[3];
3456 tmpnodes[6] = nodes[5];
3457 tmpnodes[7] = nodes[7];
3458 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3462 else { //////// polygon
3463 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3464 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3466 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3467 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3468 aMesh->ChangeElementNodes( f, nodes, nbn );
3471 while ( srcElements.Length() < myLastCreatedElems.Length() )
3472 srcElements.Append( *srcEdge );
3474 } // loop on free faces
3476 // go to the next volume
3478 while ( iVol++ < nbVolumesByStep ) v++;
3481 } // sweep free links into faces
3483 // Make a ceiling face with a normal external to a volume
3485 SMDS_VolumeTool lastVol( itElem->second.back() );
3487 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3489 lastVol.SetExternalNormal();
3490 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3491 int nbn = lastVol.NbFaceNodes( iF );
3494 if (!hasFreeLinks ||
3495 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3496 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3499 if (!hasFreeLinks ||
3500 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3501 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3504 if(itElem->second.back()->IsQuadratic()) {
3506 if (!hasFreeLinks ||
3507 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3508 nodes[1], nodes[3], nodes[5]) ) {
3509 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3510 nodes[1], nodes[3], nodes[5]));
3514 if (!hasFreeLinks ||
3515 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3516 nodes[1], nodes[3], nodes[5], nodes[7]) )
3517 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3518 nodes[1], nodes[3], nodes[5], nodes[7]));
3522 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3523 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3524 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3528 while ( srcElements.Length() < myLastCreatedElems.Length() )
3529 srcElements.Append( myLastCreatedElems.Last() );
3531 } // loop on swept elements
3534 //=======================================================================
3535 //function : RotationSweep
3537 //=======================================================================
3539 SMESH_MeshEditor::PGroupIDs
3540 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3541 const gp_Ax1& theAxis,
3542 const double theAngle,
3543 const int theNbSteps,
3544 const double theTol,
3545 const bool theMakeGroups,
3546 const bool theMakeWalls)
3548 myLastCreatedElems.Clear();
3549 myLastCreatedNodes.Clear();
3551 // source elements for each generated one
3552 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3554 MESSAGE( "RotationSweep()");
3556 aTrsf.SetRotation( theAxis, theAngle );
3558 aTrsf2.SetRotation( theAxis, theAngle/2. );
3560 gp_Lin aLine( theAxis );
3561 double aSqTol = theTol * theTol;
3563 SMESHDS_Mesh* aMesh = GetMeshDS();
3565 TNodeOfNodeListMap mapNewNodes;
3566 TElemOfVecOfNnlmiMap mapElemNewNodes;
3567 TElemOfElemListMap newElemsMap;
3570 TIDSortedElemSet::iterator itElem;
3571 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3572 const SMDS_MeshElement* elem = *itElem;
3573 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3575 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3576 newNodesItVec.reserve( elem->NbNodes() );
3578 // loop on elem nodes
3579 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3580 while ( itN->more() ) {
3581 // check if a node has been already sweeped
3582 const SMDS_MeshNode* node = cast2Node( itN->next() );
3584 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3586 aXYZ.Coord( coord[0], coord[1], coord[2] );
3587 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3589 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3590 if ( nIt == mapNewNodes.end() ) {
3591 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3592 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3595 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3597 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3598 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3599 const SMDS_MeshNode * newNode = node;
3600 for ( int i = 0; i < theNbSteps; i++ ) {
3602 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3604 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3605 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3606 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3607 myLastCreatedNodes.Append(newNode);
3608 srcNodes.Append( node );
3609 listNewNodes.push_back( newNode );
3610 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3611 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3614 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3616 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3617 myLastCreatedNodes.Append(newNode);
3618 srcNodes.Append( node );
3619 listNewNodes.push_back( newNode );
3622 listNewNodes.push_back( newNode );
3623 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3624 listNewNodes.push_back( newNode );
3631 // if current elem is quadratic and current node is not medium
3632 // we have to check - may be it is needed to insert additional nodes
3633 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3634 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3635 if(listNewNodes.size()==theNbSteps) {
3636 listNewNodes.clear();
3638 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3640 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3641 const SMDS_MeshNode * newNode = node;
3643 for(int i = 0; i<theNbSteps; i++) {
3644 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3645 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3646 cout<<" 3 AddNode: "<<newNode;
3647 myLastCreatedNodes.Append(newNode);
3648 listNewNodes.push_back( newNode );
3649 srcNodes.Append( node );
3650 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3651 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3652 cout<<" 4 AddNode: "<<newNode;
3653 myLastCreatedNodes.Append(newNode);
3654 srcNodes.Append( node );
3655 listNewNodes.push_back( newNode );
3659 listNewNodes.push_back( newNode );
3665 newNodesItVec.push_back( nIt );
3667 // make new elements
3668 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3672 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3674 PGroupIDs newGroupIDs;
3675 if ( theMakeGroups )
3676 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3682 //=======================================================================
3683 //function : CreateNode
3685 //=======================================================================
3686 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3689 const double tolnode,
3690 SMESH_SequenceOfNode& aNodes)
3692 myLastCreatedElems.Clear();
3693 myLastCreatedNodes.Clear();
3696 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3698 // try to search in sequence of existing nodes
3699 // if aNodes.Length()>0 we 'nave to use given sequence
3700 // else - use all nodes of mesh
3701 if(aNodes.Length()>0) {
3703 for(i=1; i<=aNodes.Length(); i++) {
3704 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3705 if(P1.Distance(P2)<tolnode)
3706 return aNodes.Value(i);
3710 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3711 while(itn->more()) {
3712 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3713 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3714 if(P1.Distance(P2)<tolnode)
3719 // create new node and return it
3720 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3721 myLastCreatedNodes.Append(NewNode);
3726 //=======================================================================
3727 //function : ExtrusionSweep
3729 //=======================================================================
3731 SMESH_MeshEditor::PGroupIDs
3732 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3733 const gp_Vec& theStep,
3734 const int theNbSteps,
3735 TElemOfElemListMap& newElemsMap,
3736 const bool theMakeGroups,
3738 const double theTolerance)
3740 ExtrusParam aParams;
3741 aParams.myDir = gp_Dir(theStep);
3742 aParams.myNodes.Clear();
3743 aParams.mySteps = new TColStd_HSequenceOfReal;
3745 for(i=1; i<=theNbSteps; i++)
3746 aParams.mySteps->Append(theStep.Magnitude());
3749 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3753 //=======================================================================
3754 //function : ExtrusionSweep
3756 //=======================================================================
3758 SMESH_MeshEditor::PGroupIDs
3759 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3760 ExtrusParam& theParams,
3761 TElemOfElemListMap& newElemsMap,
3762 const bool theMakeGroups,
3764 const double theTolerance)
3766 myLastCreatedElems.Clear();
3767 myLastCreatedNodes.Clear();
3769 // source elements for each generated one
3770 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3772 SMESHDS_Mesh* aMesh = GetMeshDS();
3774 int nbsteps = theParams.mySteps->Length();
3776 TNodeOfNodeListMap mapNewNodes;
3777 //TNodeOfNodeVecMap mapNewNodes;
3778 TElemOfVecOfNnlmiMap mapElemNewNodes;
3779 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3782 TIDSortedElemSet::iterator itElem;
3783 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3784 // check element type
3785 const SMDS_MeshElement* elem = *itElem;
3786 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3789 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3790 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3791 newNodesItVec.reserve( elem->NbNodes() );
3793 // loop on elem nodes
3794 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3795 while ( itN->more() )
3797 // check if a node has been already sweeped
3798 const SMDS_MeshNode* node = cast2Node( itN->next() );
3799 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3800 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3801 if ( nIt == mapNewNodes.end() ) {
3802 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3803 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3804 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3805 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3806 //vecNewNodes.reserve(nbsteps);
3809 double coord[] = { node->X(), node->Y(), node->Z() };
3810 //int nbsteps = theParams.mySteps->Length();
3811 for ( int i = 0; i < nbsteps; i++ ) {
3812 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3813 // create additional node
3814 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3815 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3816 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3817 if( theFlags & EXTRUSION_FLAG_SEW ) {
3818 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3819 theTolerance, theParams.myNodes);
3820 listNewNodes.push_back( newNode );
3823 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3824 myLastCreatedNodes.Append(newNode);
3825 srcNodes.Append( node );
3826 listNewNodes.push_back( newNode );
3829 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3830 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3831 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3832 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3833 if( theFlags & EXTRUSION_FLAG_SEW ) {
3834 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3835 theTolerance, theParams.myNodes);
3836 listNewNodes.push_back( newNode );
3837 //vecNewNodes[i]=newNode;
3840 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3841 myLastCreatedNodes.Append(newNode);
3842 srcNodes.Append( node );
3843 listNewNodes.push_back( newNode );
3844 //vecNewNodes[i]=newNode;
3849 // if current elem is quadratic and current node is not medium
3850 // we have to check - may be it is needed to insert additional nodes
3851 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3852 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3853 if(listNewNodes.size()==nbsteps) {
3854 listNewNodes.clear();
3855 double coord[] = { node->X(), node->Y(), node->Z() };
3856 for ( int i = 0; i < nbsteps; i++ ) {
3857 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3858 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3859 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3860 if( theFlags & EXTRUSION_FLAG_SEW ) {
3861 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3862 theTolerance, theParams.myNodes);
3863 listNewNodes.push_back( newNode );
3866 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3867 myLastCreatedNodes.Append(newNode);
3868 srcNodes.Append( node );
3869 listNewNodes.push_back( newNode );
3871 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3872 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3873 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3874 if( theFlags & EXTRUSION_FLAG_SEW ) {
3875 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3876 theTolerance, theParams.myNodes);
3877 listNewNodes.push_back( newNode );
3880 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3881 myLastCreatedNodes.Append(newNode);
3882 srcNodes.Append( node );
3883 listNewNodes.push_back( newNode );
3889 newNodesItVec.push_back( nIt );
3891 // make new elements
3892 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
3895 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3896 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
3898 PGroupIDs newGroupIDs;
3899 if ( theMakeGroups )
3900 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
3906 //=======================================================================
3907 //class : SMESH_MeshEditor_PathPoint
3908 //purpose : auxiliary class
3909 //=======================================================================
3910 class SMESH_MeshEditor_PathPoint {
3912 SMESH_MeshEditor_PathPoint() {
3913 myPnt.SetCoord(99., 99., 99.);
3914 myTgt.SetCoord(1.,0.,0.);
3918 void SetPnt(const gp_Pnt& aP3D){
3921 void SetTangent(const gp_Dir& aTgt){
3924 void SetAngle(const double& aBeta){
3927 void SetParameter(const double& aPrm){
3930 const gp_Pnt& Pnt()const{
3933 const gp_Dir& Tangent()const{
3936 double Angle()const{
3939 double Parameter()const{
3951 //=======================================================================
3952 //function : ExtrusionAlongTrack
3954 //=======================================================================
3955 SMESH_MeshEditor::Extrusion_Error
3956 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3957 SMESH_subMesh* theTrack,
3958 const SMDS_MeshNode* theN1,
3959 const bool theHasAngles,
3960 list<double>& theAngles,
3961 const bool theLinearVariation,
3962 const bool theHasRefPoint,
3963 const gp_Pnt& theRefPoint,
3964 const bool theMakeGroups)
3966 myLastCreatedElems.Clear();
3967 myLastCreatedNodes.Clear();
3970 std::list<double> aPrms;
3971 TIDSortedElemSet::iterator itElem;
3974 TopoDS_Edge aTrackEdge;
3975 TopoDS_Vertex aV1, aV2;
3977 SMDS_ElemIteratorPtr aItE;
3978 SMDS_NodeIteratorPtr aItN;
3979 SMDSAbs_ElementType aTypeE;
3981 TNodeOfNodeListMap mapNewNodes;
3984 aNbE = theElements.size();
3987 return EXTR_NO_ELEMENTS;
3989 // 1.1 Track Pattern
3992 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
3994 aItE = pSubMeshDS->GetElements();
3995 while ( aItE->more() ) {
3996 const SMDS_MeshElement* pE = aItE->next();
3997 aTypeE = pE->GetType();
3998 // Pattern must contain links only
3999 if ( aTypeE != SMDSAbs_Edge )
4000 return EXTR_PATH_NOT_EDGE;
4003 list<SMESH_MeshEditor_PathPoint> fullList;
4005 const TopoDS_Shape& aS = theTrack->GetSubShape();
4006 // Sub shape for the Pattern must be an Edge or Wire
4007 if( aS.ShapeType() == TopAbs_EDGE ) {
4008 aTrackEdge = TopoDS::Edge( aS );
4009 // the Edge must not be degenerated
4010 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4011 return EXTR_BAD_PATH_SHAPE;
4012 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4013 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4014 const SMDS_MeshNode* aN1 = aItN->next();
4015 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4016 const SMDS_MeshNode* aN2 = aItN->next();
4017 // starting node must be aN1 or aN2
4018 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4019 return EXTR_BAD_STARTING_NODE;
4020 aItN = pSubMeshDS->GetNodes();
4021 while ( aItN->more() ) {
4022 const SMDS_MeshNode* pNode = aItN->next();
4023 const SMDS_EdgePosition* pEPos =
4024 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4025 double aT = pEPos->GetUParameter();
4026 aPrms.push_back( aT );
4028 //Extrusion_Error err =
4029 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4031 else if( aS.ShapeType() == TopAbs_WIRE ) {
4032 list< SMESH_subMesh* > LSM;
4033 TopTools_SequenceOfShape Edges;
4034 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4035 while(itSM->more()) {
4036 SMESH_subMesh* SM = itSM->next();
4038 const TopoDS_Shape& aS = SM->GetSubShape();
4041 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4042 int startNid = theN1->GetID();
4043 TColStd_MapOfInteger UsedNums;
4044 int NbEdges = Edges.Length();
4046 for(; i<=NbEdges; i++) {
4048 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4049 for(; itLSM!=LSM.end(); itLSM++) {
4051 if(UsedNums.Contains(k)) continue;
4052 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4053 SMESH_subMesh* locTrack = *itLSM;
4054 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4055 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4056 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4057 const SMDS_MeshNode* aN1 = aItN->next();
4058 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4059 const SMDS_MeshNode* aN2 = aItN->next();
4060 // starting node must be aN1 or aN2
4061 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4062 // 2. Collect parameters on the track edge
4064 aItN = locMeshDS->GetNodes();
4065 while ( aItN->more() ) {
4066 const SMDS_MeshNode* pNode = aItN->next();
4067 const SMDS_EdgePosition* pEPos =
4068 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4069 double aT = pEPos->GetUParameter();
4070 aPrms.push_back( aT );
4072 list<SMESH_MeshEditor_PathPoint> LPP;
4073 //Extrusion_Error err =
4074 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4075 LLPPs.push_back(LPP);
4077 // update startN for search following egde
4078 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4079 else startNid = aN1->GetID();
4083 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4084 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4085 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4086 for(; itPP!=firstList.end(); itPP++) {
4087 fullList.push_back( *itPP );
4089 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4090 fullList.pop_back();
4092 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4093 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4094 itPP = currList.begin();
4095 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4096 gp_Dir D1 = PP1.Tangent();
4097 gp_Dir D2 = PP2.Tangent();
4098 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4099 (D1.Z()+D2.Z())/2 ) );
4100 PP1.SetTangent(Dnew);
4101 fullList.push_back(PP1);
4103 for(; itPP!=firstList.end(); itPP++) {
4104 fullList.push_back( *itPP );
4106 PP1 = fullList.back();
4107 fullList.pop_back();
4109 // if wire not closed
4110 fullList.push_back(PP1);
4114 return EXTR_BAD_PATH_SHAPE;
4117 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4118 theHasRefPoint, theRefPoint, theMakeGroups);
4122 //=======================================================================
4123 //function : ExtrusionAlongTrack
4125 //=======================================================================
4126 SMESH_MeshEditor::Extrusion_Error
4127 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4128 SMESH_Mesh* theTrack,
4129 const SMDS_MeshNode* theN1,
4130 const bool theHasAngles,
4131 list<double>& theAngles,
4132 const bool theLinearVariation,
4133 const bool theHasRefPoint,
4134 const gp_Pnt& theRefPoint,
4135 const bool theMakeGroups)
4137 myLastCreatedElems.Clear();
4138 myLastCreatedNodes.Clear();
4141 std::list<double> aPrms;
4142 TIDSortedElemSet::iterator itElem;
4145 TopoDS_Edge aTrackEdge;
4146 TopoDS_Vertex aV1, aV2;
4148 SMDS_ElemIteratorPtr aItE;
4149 SMDS_NodeIteratorPtr aItN;
4150 SMDSAbs_ElementType aTypeE;
4152 TNodeOfNodeListMap mapNewNodes;
4155 aNbE = theElements.size();
4158 return EXTR_NO_ELEMENTS;
4160 // 1.1 Track Pattern
4163 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4165 aItE = pMeshDS->elementsIterator();
4166 while ( aItE->more() ) {
4167 const SMDS_MeshElement* pE = aItE->next();
4168 aTypeE = pE->GetType();
4169 // Pattern must contain links only
4170 if ( aTypeE != SMDSAbs_Edge )
4171 return EXTR_PATH_NOT_EDGE;
4174 list<SMESH_MeshEditor_PathPoint> fullList;
4176 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4177 // Sub shape for the Pattern must be an Edge or Wire
4178 if( aS.ShapeType() == TopAbs_EDGE ) {
4179 aTrackEdge = TopoDS::Edge( aS );
4180 // the Edge must not be degenerated
4181 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4182 return EXTR_BAD_PATH_SHAPE;
4183 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4184 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4185 const SMDS_MeshNode* aN1 = aItN->next();
4186 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4187 const SMDS_MeshNode* aN2 = aItN->next();
4188 // starting node must be aN1 or aN2
4189 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4190 return EXTR_BAD_STARTING_NODE;
4191 aItN = pMeshDS->nodesIterator();
4192 while ( aItN->more() ) {
4193 const SMDS_MeshNode* pNode = aItN->next();
4194 if( pNode==aN1 || pNode==aN2 ) continue;
4195 const SMDS_EdgePosition* pEPos =
4196 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4197 double aT = pEPos->GetUParameter();
4198 aPrms.push_back( aT );
4200 //Extrusion_Error err =
4201 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4203 else if( aS.ShapeType() == TopAbs_WIRE ) {
4204 list< SMESH_subMesh* > LSM;
4205 TopTools_SequenceOfShape Edges;
4206 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4207 for(; eExp.More(); eExp.Next()) {
4208 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4209 if( BRep_Tool::Degenerated(E) ) continue;
4210 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4216 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4217 int startNid = theN1->GetID();
4218 TColStd_MapOfInteger UsedNums;
4219 int NbEdges = Edges.Length();
4221 for(; i<=NbEdges; i++) {
4223 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4224 for(; itLSM!=LSM.end(); itLSM++) {
4226 if(UsedNums.Contains(k)) continue;
4227 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4228 SMESH_subMesh* locTrack = *itLSM;
4229 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4230 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4231 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4232 const SMDS_MeshNode* aN1 = aItN->next();
4233 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4234 const SMDS_MeshNode* aN2 = aItN->next();
4235 // starting node must be aN1 or aN2
4236 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4237 // 2. Collect parameters on the track edge
4239 aItN = locMeshDS->GetNodes();
4240 while ( aItN->more() ) {
4241 const SMDS_MeshNode* pNode = aItN->next();
4242 const SMDS_EdgePosition* pEPos =
4243 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4244 double aT = pEPos->GetUParameter();
4245 aPrms.push_back( aT );
4247 list<SMESH_MeshEditor_PathPoint> LPP;
4248 //Extrusion_Error err =
4249 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4250 LLPPs.push_back(LPP);
4252 // update startN for search following egde
4253 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4254 else startNid = aN1->GetID();
4258 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4259 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4260 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4261 for(; itPP!=firstList.end(); itPP++) {
4262 fullList.push_back( *itPP );
4264 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4265 fullList.pop_back();
4267 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4268 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4269 itPP = currList.begin();
4270 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4271 gp_Pnt P1 = PP1.Pnt();
4272 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4273 gp_Pnt P2 = PP2.Pnt();
4274 gp_Dir D1 = PP1.Tangent();
4275 gp_Dir D2 = PP2.Tangent();
4276 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4277 (D1.Z()+D2.Z())/2 ) );
4278 PP1.SetTangent(Dnew);
4279 fullList.push_back(PP1);
4281 for(; itPP!=currList.end(); itPP++) {
4282 fullList.push_back( *itPP );
4284 PP1 = fullList.back();
4285 fullList.pop_back();
4287 // if wire not closed
4288 fullList.push_back(PP1);
4292 return EXTR_BAD_PATH_SHAPE;
4295 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4296 theHasRefPoint, theRefPoint, theMakeGroups);
4300 //=======================================================================
4301 //function : MakeEdgePathPoints
4302 //purpose : auxilary for ExtrusionAlongTrack
4303 //=======================================================================
4304 SMESH_MeshEditor::Extrusion_Error
4305 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4306 const TopoDS_Edge& aTrackEdge,
4308 list<SMESH_MeshEditor_PathPoint>& LPP)
4310 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4312 aTolVec2=aTolVec*aTolVec;
4314 TopoDS_Vertex aV1, aV2;
4315 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4316 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4317 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4318 // 2. Collect parameters on the track edge
4319 aPrms.push_front( aT1 );
4320 aPrms.push_back( aT2 );
4323 if( FirstIsStart ) {
4334 SMESH_MeshEditor_PathPoint aPP;
4335 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4336 std::list<double>::iterator aItD = aPrms.begin();
4337 for(; aItD != aPrms.end(); ++aItD) {
4341 aC3D->D1( aT, aP3D, aVec );
4342 aL2 = aVec.SquareMagnitude();
4343 if ( aL2 < aTolVec2 )
4344 return EXTR_CANT_GET_TANGENT;
4345 gp_Dir aTgt( aVec );
4347 aPP.SetTangent( aTgt );
4348 aPP.SetParameter( aT );
4355 //=======================================================================
4356 //function : MakeExtrElements
4357 //purpose : auxilary for ExtrusionAlongTrack
4358 //=======================================================================
4359 SMESH_MeshEditor::Extrusion_Error
4360 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4361 list<SMESH_MeshEditor_PathPoint>& fullList,
4362 const bool theHasAngles,
4363 list<double>& theAngles,
4364 const bool theLinearVariation,
4365 const bool theHasRefPoint,
4366 const gp_Pnt& theRefPoint,
4367 const bool theMakeGroups)
4369 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4370 int aNbTP = fullList.size();
4371 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4373 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4374 LinearAngleVariation(aNbTP-1, theAngles);
4376 vector<double> aAngles( aNbTP );
4378 for(; j<aNbTP; ++j) {
4381 if ( theHasAngles ) {
4383 std::list<double>::iterator aItD = theAngles.begin();
4384 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4386 aAngles[j] = anAngle;
4389 // fill vector of path points with angles
4390 //aPPs.resize(fullList.size());
4392 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4393 for(; itPP!=fullList.end(); itPP++) {
4395 SMESH_MeshEditor_PathPoint PP = *itPP;
4396 PP.SetAngle(aAngles[j]);
4400 TNodeOfNodeListMap mapNewNodes;
4401 TElemOfVecOfNnlmiMap mapElemNewNodes;
4402 TElemOfElemListMap newElemsMap;
4403 TIDSortedElemSet::iterator itElem;
4406 SMDSAbs_ElementType aTypeE;
4407 // source elements for each generated one
4408 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4410 // 3. Center of rotation aV0
4411 gp_Pnt aV0 = theRefPoint;
4413 if ( !theHasRefPoint ) {
4415 aGC.SetCoord( 0.,0.,0. );
4417 itElem = theElements.begin();
4418 for ( ; itElem != theElements.end(); itElem++ ) {
4419 const SMDS_MeshElement* elem = *itElem;
4421 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4422 while ( itN->more() ) {
4423 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4428 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4429 list<const SMDS_MeshNode*> aLNx;
4430 mapNewNodes[node] = aLNx;
4432 gp_XYZ aXYZ( aX, aY, aZ );
4440 } // if (!theHasRefPoint) {
4441 mapNewNodes.clear();
4443 // 4. Processing the elements
4444 SMESHDS_Mesh* aMesh = GetMeshDS();
4446 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4447 // check element type
4448 const SMDS_MeshElement* elem = *itElem;
4449 aTypeE = elem->GetType();
4450 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4453 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4454 newNodesItVec.reserve( elem->NbNodes() );
4456 // loop on elem nodes
4458 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4459 while ( itN->more() )
4462 // check if a node has been already processed
4463 const SMDS_MeshNode* node =
4464 static_cast<const SMDS_MeshNode*>( itN->next() );
4465 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4466 if ( nIt == mapNewNodes.end() ) {
4467 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4468 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4471 aX = node->X(); aY = node->Y(); aZ = node->Z();
4473 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4474 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4475 gp_Ax1 anAx1, anAxT1T0;
4476 gp_Dir aDT1x, aDT0x, aDT1T0;
4481 aPN0.SetCoord(aX, aY, aZ);
4483 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4485 aDT0x= aPP0.Tangent();
4486 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4488 for ( j = 1; j < aNbTP; ++j ) {
4489 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4491 aDT1x = aPP1.Tangent();
4492 aAngle1x = aPP1.Angle();
4494 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4496 gp_Vec aV01x( aP0x, aP1x );
4497 aTrsf.SetTranslation( aV01x );
4500 aV1x = aV0x.Transformed( aTrsf );
4501 aPN1 = aPN0.Transformed( aTrsf );
4503 // rotation 1 [ T1,T0 ]
4504 aAngleT1T0=-aDT1x.Angle( aDT0x );
4505 if (fabs(aAngleT1T0) > aTolAng) {
4507 anAxT1T0.SetLocation( aV1x );
4508 anAxT1T0.SetDirection( aDT1T0 );
4509 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4511 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4515 if ( theHasAngles ) {
4516 anAx1.SetLocation( aV1x );
4517 anAx1.SetDirection( aDT1x );
4518 aTrsfRot.SetRotation( anAx1, aAngle1x );
4520 aPN1 = aPN1.Transformed( aTrsfRot );
4524 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4525 // create additional node
4526 double x = ( aPN1.X() + aPN0.X() )/2.;
4527 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4528 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4529 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4530 myLastCreatedNodes.Append(newNode);
4531 srcNodes.Append( node );
4532 listNewNodes.push_back( newNode );
4537 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4538 myLastCreatedNodes.Append(newNode);
4539 srcNodes.Append( node );
4540 listNewNodes.push_back( newNode );
4550 // if current elem is quadratic and current node is not medium
4551 // we have to check - may be it is needed to insert additional nodes
4552 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4553 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4554 if(listNewNodes.size()==aNbTP-1) {
4555 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4556 gp_XYZ P(node->X(), node->Y(), node->Z());
4557 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4559 for(i=0; i<aNbTP-1; i++) {
4560 const SMDS_MeshNode* N = *it;
4561 double x = ( N->X() + P.X() )/2.;
4562 double y = ( N->Y() + P.Y() )/2.;
4563 double z = ( N->Z() + P.Z() )/2.;
4564 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4565 srcNodes.Append( node );
4566 myLastCreatedNodes.Append(newN);
4569 P = gp_XYZ(N->X(),N->Y(),N->Z());
4571 listNewNodes.clear();
4572 for(i=0; i<2*(aNbTP-1); i++) {
4573 listNewNodes.push_back(aNodes[i]);
4579 newNodesItVec.push_back( nIt );
4581 // make new elements
4582 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4583 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4584 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4587 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4589 if ( theMakeGroups )
4590 generateGroups( srcNodes, srcElems, "extruded");
4596 //=======================================================================
4597 //function : LinearAngleVariation
4598 //purpose : auxilary for ExtrusionAlongTrack
4599 //=======================================================================
4600 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4601 list<double>& Angles)
4603 int nbAngles = Angles.size();
4604 if( nbSteps > nbAngles ) {
4605 vector<double> theAngles(nbAngles);
4606 list<double>::iterator it = Angles.begin();
4608 for(; it!=Angles.end(); it++) {
4610 theAngles[i] = (*it);
4613 double rAn2St = double( nbAngles ) / double( nbSteps );
4614 double angPrev = 0, angle;
4615 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4616 double angCur = rAn2St * ( iSt+1 );
4617 double angCurFloor = floor( angCur );
4618 double angPrevFloor = floor( angPrev );
4619 if ( angPrevFloor == angCurFloor )
4620 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4622 int iP = int( angPrevFloor );
4623 double angPrevCeil = ceil(angPrev);
4624 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4626 int iC = int( angCurFloor );
4627 if ( iC < nbAngles )
4628 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4630 iP = int( angPrevCeil );
4632 angle += theAngles[ iC ];
4634 res.push_back(angle);
4639 for(; it!=res.end(); it++)
4640 Angles.push_back( *it );
4645 //=======================================================================
4646 //function : Transform
4648 //=======================================================================
4650 SMESH_MeshEditor::PGroupIDs
4651 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4652 const gp_Trsf& theTrsf,
4654 const bool theMakeGroups,
4655 SMESH_Mesh* theTargetMesh)
4657 myLastCreatedElems.Clear();
4658 myLastCreatedNodes.Clear();
4660 bool needReverse = false;
4661 string groupPostfix;
4662 switch ( theTrsf.Form() ) {
4667 groupPostfix = "mirrored";
4670 groupPostfix = "rotated";
4672 case gp_Translation:
4673 groupPostfix = "translated";
4676 groupPostfix = "scaled";
4679 needReverse = false;
4680 groupPostfix = "transformed";
4683 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4684 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4685 SMESHDS_Mesh* aMesh = GetMeshDS();
4688 // map old node to new one
4689 TNodeNodeMap nodeMap;
4691 // elements sharing moved nodes; those of them which have all
4692 // nodes mirrored but are not in theElems are to be reversed
4693 TIDSortedElemSet inverseElemSet;
4695 // source elements for each generated one
4696 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4699 TIDSortedElemSet::iterator itElem;
4700 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4701 const SMDS_MeshElement* elem = *itElem;
4705 // loop on elem nodes
4706 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4707 while ( itN->more() ) {
4709 // check if a node has been already transformed
4710 const SMDS_MeshNode* node = cast2Node( itN->next() );
4711 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4712 nodeMap.insert( make_pair ( node, node ));
4713 if ( !n2n_isnew.second )
4717 coord[0] = node->X();
4718 coord[1] = node->Y();
4719 coord[2] = node->Z();
4720 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4721 if ( theTargetMesh ) {
4722 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4723 n2n_isnew.first->second = newNode;
4724 myLastCreatedNodes.Append(newNode);
4725 srcNodes.Append( node );
4727 else if ( theCopy ) {
4728 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4729 n2n_isnew.first->second = newNode;
4730 myLastCreatedNodes.Append(newNode);
4731 srcNodes.Append( node );
4734 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4735 // node position on shape becomes invalid
4736 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4737 ( SMDS_SpacePosition::originSpacePosition() );
4740 // keep inverse elements
4741 if ( !theCopy && !theTargetMesh && needReverse ) {
4742 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4743 while ( invElemIt->more() ) {
4744 const SMDS_MeshElement* iel = invElemIt->next();
4745 inverseElemSet.insert( iel );
4751 // either create new elements or reverse mirrored ones
4752 if ( !theCopy && !needReverse && !theTargetMesh )
4755 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4756 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4757 theElems.insert( *invElemIt );
4759 // replicate or reverse elements
4762 REV_TETRA = 0, // = nbNodes - 4
4763 REV_PYRAMID = 1, // = nbNodes - 4
4764 REV_PENTA = 2, // = nbNodes - 4
4766 REV_HEXA = 4, // = nbNodes - 4
4770 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4771 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4772 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4773 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4774 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4775 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4778 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4780 const SMDS_MeshElement* elem = *itElem;
4781 if ( !elem || elem->GetType() == SMDSAbs_Node )
4784 int nbNodes = elem->NbNodes();
4785 int elemType = elem->GetType();
4787 if (elem->IsPoly()) {
4788 // Polygon or Polyhedral Volume
4789 switch ( elemType ) {
4792 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4794 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4795 while (itN->more()) {
4796 const SMDS_MeshNode* node =
4797 static_cast<const SMDS_MeshNode*>(itN->next());
4798 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4799 if (nodeMapIt == nodeMap.end())
4800 break; // not all nodes transformed
4802 // reverse mirrored faces and volumes
4803 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4805 poly_nodes[iNode] = (*nodeMapIt).second;
4809 if ( iNode != nbNodes )
4810 continue; // not all nodes transformed
4812 if ( theTargetMesh ) {
4813 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4814 srcElems.Append( elem );
4816 else if ( theCopy ) {
4817 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4818 srcElems.Append( elem );
4821 aMesh->ChangePolygonNodes(elem, poly_nodes);
4825 case SMDSAbs_Volume:
4827 // ATTENTION: Reversing is not yet done!!!
4828 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4829 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4831 MESSAGE("Warning: bad volumic element");
4835 vector<const SMDS_MeshNode*> poly_nodes;
4836 vector<int> quantities;
4838 bool allTransformed = true;
4839 int nbFaces = aPolyedre->NbFaces();
4840 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4841 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4842 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4843 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4844 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4845 if (nodeMapIt == nodeMap.end()) {
4846 allTransformed = false; // not all nodes transformed
4848 poly_nodes.push_back((*nodeMapIt).second);
4851 quantities.push_back(nbFaceNodes);
4853 if ( !allTransformed )
4854 continue; // not all nodes transformed
4856 if ( theTargetMesh ) {
4857 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4858 srcElems.Append( elem );
4860 else if ( theCopy ) {
4861 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4862 srcElems.Append( elem );
4865 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4875 int* i = index[ FORWARD ];
4876 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4877 if ( elemType == SMDSAbs_Face )
4878 i = index[ REV_FACE ];
4880 i = index[ nbNodes - 4 ];
4882 if(elem->IsQuadratic()) {
4883 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4886 if(nbNodes==3) { // quadratic edge
4887 static int anIds[] = {1,0,2};
4890 else if(nbNodes==6) { // quadratic triangle
4891 static int anIds[] = {0,2,1,5,4,3};
4894 else if(nbNodes==8) { // quadratic quadrangle
4895 static int anIds[] = {0,3,2,1,7,6,5,4};
4898 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4899 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4902 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4903 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4906 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4907 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4910 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4911 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4917 // find transformed nodes
4918 vector<const SMDS_MeshNode*> nodes(nbNodes);
4920 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4921 while ( itN->more() ) {
4922 const SMDS_MeshNode* node =
4923 static_cast<const SMDS_MeshNode*>( itN->next() );
4924 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4925 if ( nodeMapIt == nodeMap.end() )
4926 break; // not all nodes transformed
4927 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4929 if ( iNode != nbNodes )
4930 continue; // not all nodes transformed
4932 if ( theTargetMesh ) {
4933 if ( SMDS_MeshElement* copy =
4934 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4935 myLastCreatedElems.Append( copy );
4936 srcElems.Append( elem );
4939 else if ( theCopy ) {
4940 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4941 myLastCreatedElems.Append( copy );
4942 srcElems.Append( elem );
4946 // reverse element as it was reversed by transformation
4948 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4952 PGroupIDs newGroupIDs;
4954 if ( theMakeGroups && theCopy ||
4955 theMakeGroups && theTargetMesh )
4956 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4961 //=======================================================================
4963 * \brief Create groups of elements made during transformation
4964 * \param nodeGens - nodes making corresponding myLastCreatedNodes
4965 * \param elemGens - elements making corresponding myLastCreatedElems
4966 * \param postfix - to append to names of new groups
4968 //=======================================================================
4970 SMESH_MeshEditor::PGroupIDs
4971 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4972 const SMESH_SequenceOfElemPtr& elemGens,
4973 const std::string& postfix,
4974 SMESH_Mesh* targetMesh)
4976 PGroupIDs newGroupIDs( new list<int> );
4977 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4979 // Sort existing groups by types and collect their names
4981 // to store an old group and a generated new one
4982 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4983 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4985 set< string > groupNames;
4987 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4988 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4989 while ( groupIt->more() ) {
4990 SMESH_Group * group = groupIt->next();
4991 if ( !group ) continue;
4992 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4993 if ( !groupDS || groupDS->IsEmpty() ) continue;
4994 groupNames.insert( group->GetName() );
4995 groupDS->SetStoreName( group->GetName() );
4996 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5001 // loop on nodes and elements
5002 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5004 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5005 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5006 if ( gens.Length() != elems.Length() )
5007 throw SALOME_Exception(LOCALIZED("invalid args"));
5009 // loop on created elements
5010 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5012 const SMDS_MeshElement* sourceElem = gens( iElem );
5013 if ( !sourceElem ) {
5014 MESSAGE("generateGroups(): NULL source element");
5017 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5018 if ( groupsOldNew.empty() ) {
5019 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5020 ++iElem; // skip all elements made by sourceElem
5023 // collect all elements made by sourceElem
5024 list< const SMDS_MeshElement* > resultElems;
5025 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5026 if ( resElem != sourceElem )
5027 resultElems.push_back( resElem );
5028 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5029 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5030 if ( resElem != sourceElem )
5031 resultElems.push_back( resElem );
5032 // do not generate element groups from node ones
5033 if ( sourceElem->GetType() == SMDSAbs_Node &&
5034 elems( iElem )->GetType() != SMDSAbs_Node )
5037 // add resultElems to groups made by ones the sourceElem belongs to
5038 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5039 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5041 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5042 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5044 SMDS_MeshGroup* & newGroup = gOldNew->second;
5045 if ( !newGroup )// create a new group
5048 string name = oldGroup->GetStoreName();
5049 if ( !targetMesh ) {
5053 while ( !groupNames.insert( name ).second ) // name exists
5059 TCollection_AsciiString nbStr(nb+1);
5060 name.resize( name.rfind('_')+1 );
5061 name += nbStr.ToCString();
5068 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5070 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5071 newGroup = & groupDS->SMDSGroup();
5072 newGroupIDs->push_back( id );
5075 // fill in a new group
5076 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5077 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5078 newGroup->Add( *resElemIt );
5081 } // loop on created elements
5082 }// loop on nodes and elements
5087 //================================================================================
5089 * \brief Return list of group of nodes close to each other within theTolerance
5090 * Search among theNodes or in the whole mesh if theNodes is empty using
5091 * an Octree algorithm
5093 //================================================================================
5095 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5096 const double theTolerance,
5097 TListOfListOfNodes & theGroupsOfNodes)
5099 myLastCreatedElems.Clear();
5100 myLastCreatedNodes.Clear();
5102 set<const SMDS_MeshNode*> nodes;
5103 if ( theNodes.empty() )
5104 { // get all nodes in the mesh
5105 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5106 while ( nIt->more() )
5107 nodes.insert( nodes.end(),nIt->next());
5112 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5116 //=======================================================================
5118 * \brief Implementation of search for the node closest to point
5120 //=======================================================================
5122 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5124 //---------------------------------------------------------------------
5126 * \brief Constructor
5128 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5130 myMesh = ( SMESHDS_Mesh* ) theMesh;
5132 set<const SMDS_MeshNode*> nodes;
5134 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5135 while ( nIt->more() )
5136 nodes.insert( nodes.end(), nIt->next() );
5138 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5140 // get max size of a leaf box
5141 SMESH_OctreeNode* tree = myOctreeNode;
5142 while ( !tree->isLeaf() )
5144 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5148 myHalfLeafSize = tree->maxSize() / 2.;
5151 //---------------------------------------------------------------------
5153 * \brief Move node and update myOctreeNode accordingly
5155 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5157 myOctreeNode->UpdateByMoveNode( node, toPnt );
5158 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5161 //---------------------------------------------------------------------
5163 * \brief Do it's job
5165 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5167 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5168 map<double, const SMDS_MeshNode*> dist2Nodes;
5169 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5170 if ( !dist2Nodes.empty() )
5171 return dist2Nodes.begin()->second;
5172 list<const SMDS_MeshNode*> nodes;
5173 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5175 double minSqDist = DBL_MAX;
5176 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5178 // sort leafs by their distance from thePnt
5179 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5180 TDistTreeMap treeMap;
5181 list< SMESH_OctreeNode* > treeList;
5182 list< SMESH_OctreeNode* >::iterator trIt;
5183 treeList.push_back( myOctreeNode );
5185 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5186 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5188 SMESH_OctreeNode* tree = *trIt;
5189 if ( !tree->isLeaf() ) // put children to the queue
5191 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5192 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5193 while ( cIt->more() )
5194 treeList.push_back( cIt->next() );
5196 else if ( tree->NbNodes() ) // put a tree to the treeMap
5198 const Bnd_B3d& box = tree->getBox();
5199 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5200 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5201 if ( !it_in.second ) // not unique distance to box center
5202 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5205 // find distance after which there is no sense to check tree's
5206 double sqLimit = DBL_MAX;
5207 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5208 if ( treeMap.size() > 5 ) {
5209 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5210 const Bnd_B3d& box = closestTree->getBox();
5211 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5212 sqLimit = limit * limit;
5214 // get all nodes from trees
5215 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5216 if ( sqDist_tree->first > sqLimit )
5218 SMESH_OctreeNode* tree = sqDist_tree->second;
5219 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5222 // find closest among nodes
5223 minSqDist = DBL_MAX;
5224 const SMDS_MeshNode* closestNode = 0;
5225 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5226 for ( ; nIt != nodes.end(); ++nIt ) {
5227 double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
5228 if ( minSqDist > sqDist ) {
5236 //---------------------------------------------------------------------
5240 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5242 //---------------------------------------------------------------------
5244 * \brief Return the node tree
5246 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5249 SMESH_OctreeNode* myOctreeNode;
5250 SMESHDS_Mesh* myMesh;
5251 double myHalfLeafSize; // max size of a leaf box
5254 //=======================================================================
5256 * \brief Return SMESH_NodeSearcher
5258 //=======================================================================
5260 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5262 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5265 // ========================================================================
5266 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5268 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5269 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5270 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5272 //=======================================================================
5274 * \brief Octal tree of bounding boxes of elements
5276 //=======================================================================
5278 class ElementBndBoxTree : public SMESH_Octree
5282 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5283 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5284 ~ElementBndBoxTree();
5287 ElementBndBoxTree() {}
5288 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5289 void buildChildrenData();
5290 Bnd_B3d* buildRootBox();
5292 //!< Bounding box of element
5293 struct ElementBox : public Bnd_B3d
5295 const SMDS_MeshElement* _element;
5296 int _refCount; // an ElementBox can be included in several tree branches
5297 ElementBox(const SMDS_MeshElement* elem);
5299 vector< ElementBox* > _elements;
5302 //================================================================================
5304 * \brief ElementBndBoxTree creation
5306 //================================================================================
5308 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5309 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5311 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5312 _elements.reserve( nbElems );
5314 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5315 while ( elemIt->more() )
5316 _elements.push_back( new ElementBox( elemIt->next() ));
5318 if ( _elements.size() > MaxNbElemsInLeaf )
5324 //================================================================================
5328 //================================================================================
5330 ElementBndBoxTree::~ElementBndBoxTree()
5332 for ( int i = 0; i < _elements.size(); ++i )
5333 if ( --_elements[i]->_refCount <= 0 )
5334 delete _elements[i];
5337 //================================================================================
5339 * \brief Return the maximal box
5341 //================================================================================
5343 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5345 Bnd_B3d* box = new Bnd_B3d;
5346 for ( int i = 0; i < _elements.size(); ++i )
5347 box->Add( *_elements[i] );
5351 //================================================================================
5353 * \brief Redistrubute element boxes among children
5355 //================================================================================
5357 void ElementBndBoxTree::buildChildrenData()
5359 for ( int i = 0; i < _elements.size(); ++i )
5361 for (int j = 0; j < 8; j++)
5363 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5365 _elements[i]->_refCount++;
5366 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5369 _elements[i]->_refCount--;
5373 for (int j = 0; j < 8; j++)
5375 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5376 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5377 child->myIsLeaf = true;
5379 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5380 child->_elements.resize( child->_elements.size() ); // compact
5384 //================================================================================
5386 * \brief Return elements which can include the point
5388 //================================================================================
5390 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5391 TIDSortedElemSet& foundElems)
5393 if ( level() && getBox().IsOut( point.XYZ() ))
5398 for ( int i = 0; i < _elements.size(); ++i )
5399 if ( !_elements[i]->IsOut( point.XYZ() ))
5400 foundElems.insert( _elements[i]->_element );
5404 for (int i = 0; i < 8; i++)
5405 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5409 //================================================================================
5411 * \brief Construct the element box
5413 //================================================================================
5415 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5419 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5420 while ( nIt->more() )
5421 Add( TNodeXYZ( cast2Node( nIt->next() )));
5422 Enlarge( NodeRadius );
5427 //=======================================================================
5429 * \brief Implementation of search for the elements by point
5431 //=======================================================================
5433 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5435 SMESHDS_Mesh* _mesh;
5436 ElementBndBoxTree* _ebbTree;
5437 SMESH_NodeSearcherImpl* _nodeSearcher;
5438 SMDSAbs_ElementType _elementType;
5440 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh ): _mesh(&mesh),_ebbTree(0),_nodeSearcher(0) {}
5441 ~SMESH_ElementSearcherImpl()
5443 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
5444 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5448 * \brief Return elements of given type where the given point is IN or ON.
5450 * 'ALL' type means elements of any type excluding nodes and 0D elements
5452 void FindElementsByPoint(const gp_Pnt& point,
5453 SMDSAbs_ElementType type,
5454 vector< const SMDS_MeshElement* >& foundElements)
5456 foundElements.clear();
5458 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5460 // -----------------
5462 // -----------------
5463 double tolerance = 0;
5464 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5466 double boxSize = _nodeSearcher->getTree()->maxSize();
5467 tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
5469 else if ( _ebbTree && meshInfo.NbElements() > 0 )
5471 double boxSize = _ebbTree->maxSize();
5472 tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
5474 if ( tolerance == 0 )
5476 // define tolerance by size of a most complex element
5477 int complexType = SMDSAbs_Volume;
5478 while ( complexType > SMDSAbs_All &&
5479 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
5481 if ( complexType == SMDSAbs_All ) return; // empty mesh
5484 if ( complexType == int( SMDSAbs_Node ))
5486 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
5488 if ( meshInfo.NbNodes() > 2 )
5489 elemSize = TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
5493 const SMDS_MeshElement* elem =
5494 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
5495 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
5496 TNodeXYZ n1( cast2Node( nodeIt->next() ));
5497 while ( nodeIt->more() )
5499 double dist = n1.Distance( cast2Node( nodeIt->next() ));
5500 elemSize = max( dist, elemSize );
5503 tolerance = 1e-6 * elemSize;
5506 // =================================================================================
5507 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
5509 if ( !_nodeSearcher )
5510 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
5512 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
5513 if ( !closeNode ) return;
5515 if ( point.Distance( TNodeXYZ( closeNode )) > tolerance )
5516 return; // to far from any node
5518 if ( type == SMDSAbs_Node )
5520 foundElements.push_back( closeNode );
5524 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
5525 while ( elemIt->more() )
5526 foundElements.push_back( elemIt->next() );
5529 // =================================================================================
5530 else // elements more complex than 0D
5532 if ( !_ebbTree || _elementType != type )
5534 if ( _ebbTree ) delete _ebbTree;
5535 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
5537 TIDSortedElemSet suspectElems;
5538 _ebbTree->getElementsNearPoint( point, suspectElems );
5539 TIDSortedElemSet::iterator elem = suspectElems.begin();
5540 for ( ; elem != suspectElems.end(); ++elem )
5541 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
5542 foundElements.push_back( *elem );
5545 }; // struct SMESH_ElementSearcherImpl
5547 //=======================================================================
5549 * \brief Return SMESH_ElementSearcher
5551 //=======================================================================
5553 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
5555 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
5558 //=======================================================================
5560 * \brief Return true if the point is IN or ON of the element
5562 //=======================================================================
5564 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
5566 if ( element->GetType() == SMDSAbs_Volume)
5568 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
5571 // get ordered nodes
5573 vector< gp_XYZ > xyz;
5575 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
5576 if ( element->IsQuadratic() )
5577 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
5578 nodeIt = f->interlacedNodesElemIterator();
5579 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
5580 nodeIt = e->interlacedNodesElemIterator();
5582 while ( nodeIt->more() )
5583 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
5585 int i, nbNodes = element->NbNodes();
5587 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
5589 // compute face normal
5590 gp_Vec faceNorm(0,0,0);
5591 xyz.push_back( xyz.front() );
5592 for ( i = 0; i < nbNodes; ++i )
5594 gp_Vec edge1( xyz[i+1], xyz[i]);
5595 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
5596 faceNorm += edge1 ^ edge2;
5598 double normSize = faceNorm.Magnitude();
5599 if ( normSize <= tol )
5601 // degenerated face: point is out if it is out of all face edges
5602 for ( i = 0; i < nbNodes; ++i )
5604 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
5605 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
5606 SMDS_MeshEdge edge( &n1, &n2 );
5607 if ( !isOut( &edge, point, tol ))
5612 faceNorm /= normSize;
5614 // check if the point lays on face plane
5615 gp_Vec n2p( xyz[0], point );
5616 if ( fabs( n2p * faceNorm ) > tol )
5617 return true; // not on face plane
5619 // check if point is out of face boundary:
5620 // define it by closest transition of a ray point->infinity through face boundary
5621 // on the face plane.
5622 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
5623 // to find intersections of the ray with the boundary.
5625 gp_Vec plnNorm = ray ^ faceNorm;
5626 normSize = plnNorm.Magnitude();
5627 if ( normSize <= tol ) return false; // point coincides with the first node
5628 plnNorm /= normSize;
5629 // for each node of the face, compute its signed distance to the plane
5630 vector<double> dist( nbNodes + 1);
5631 for ( i = 0; i < nbNodes; ++i )
5633 gp_Vec n2p( xyz[i], point );
5634 dist[i] = n2p * plnNorm;
5636 dist.back() = dist.front();
5637 // find the closest intersection
5639 double rClosest, distClosest = 1e100;;
5641 for ( i = 0; i < nbNodes; ++i )
5644 if ( fabs( dist[i]) < tol )
5646 else if ( fabs( dist[i+1]) < tol )
5648 else if ( dist[i] * dist[i+1] < 0 )
5649 r = dist[i] / ( dist[i] - dist[i+1] );
5651 continue; // no intersection
5652 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
5653 gp_Vec p2int ( point, pInt);
5654 if ( p2int * ray > -tol ) // right half-space
5656 double intDist = p2int.SquareMagnitude();
5657 if ( intDist < distClosest )
5662 distClosest = intDist;
5667 return true; // no intesections - out
5669 // analyse transition
5670 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
5671 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
5672 gp_Vec p2int ( point, pClosest );
5673 bool out = (edgeNorm * p2int) < -tol;
5674 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
5677 // ray pass through a face node; analyze transition through an adjacent edge
5678 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
5679 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
5680 gp_Vec edgeAdjacent( p1, p2 );
5681 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
5682 bool out2 = (edgeNorm2 * p2int) < -tol;
5684 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
5685 return covexCorner ? (out || out2) : (out && out2);
5687 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
5689 // point is out of edge if it is NOT ON any straight part of edge
5690 // (we consider quadratic edge as being composed of two straight parts)
5691 for ( i = 1; i < nbNodes; ++i )
5693 gp_Vec edge( xyz[i-1], xyz[i]);
5694 gp_Vec n1p ( xyz[i-1], point);
5695 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
5698 gp_Vec n2p( xyz[i], point );
5699 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
5701 return false; // point is ON this part
5705 // Node or 0D element -------------------------------------------------------------------------
5707 gp_Vec n2p ( xyz[0], point );
5708 return n2p.Magnitude() <= tol;
5713 //=======================================================================
5714 //function : SimplifyFace
5716 //=======================================================================
5717 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5718 vector<const SMDS_MeshNode *>& poly_nodes,
5719 vector<int>& quantities) const
5721 int nbNodes = faceNodes.size();
5726 set<const SMDS_MeshNode*> nodeSet;
5728 // get simple seq of nodes
5729 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5730 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5731 int iSimple = 0, nbUnique = 0;
5733 simpleNodes[iSimple++] = faceNodes[0];
5735 for (int iCur = 1; iCur < nbNodes; iCur++) {
5736 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5737 simpleNodes[iSimple++] = faceNodes[iCur];
5738 if (nodeSet.insert( faceNodes[iCur] ).second)
5742 int nbSimple = iSimple;
5743 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5753 bool foundLoop = (nbSimple > nbUnique);
5756 set<const SMDS_MeshNode*> loopSet;
5757 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5758 const SMDS_MeshNode* n = simpleNodes[iSimple];
5759 if (!loopSet.insert( n ).second) {
5763 int iC = 0, curLast = iSimple;
5764 for (; iC < curLast; iC++) {
5765 if (simpleNodes[iC] == n) break;
5767 int loopLen = curLast - iC;
5769 // create sub-element
5771 quantities.push_back(loopLen);
5772 for (; iC < curLast; iC++) {
5773 poly_nodes.push_back(simpleNodes[iC]);
5776 // shift the rest nodes (place from the first loop position)
5777 for (iC = curLast + 1; iC < nbSimple; iC++) {
5778 simpleNodes[iC - loopLen] = simpleNodes[iC];
5780 nbSimple -= loopLen;
5783 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5784 } // while (foundLoop)
5788 quantities.push_back(iSimple);
5789 for (int i = 0; i < iSimple; i++)
5790 poly_nodes.push_back(simpleNodes[i]);
5796 //=======================================================================
5797 //function : MergeNodes
5798 //purpose : In each group, the cdr of nodes are substituted by the first one
5800 //=======================================================================
5802 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5804 myLastCreatedElems.Clear();
5805 myLastCreatedNodes.Clear();
5807 SMESHDS_Mesh* aMesh = GetMeshDS();
5809 TNodeNodeMap nodeNodeMap; // node to replace - new node
5810 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5811 list< int > rmElemIds, rmNodeIds;
5813 // Fill nodeNodeMap and elems
5815 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5816 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5817 list<const SMDS_MeshNode*>& nodes = *grIt;
5818 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5819 const SMDS_MeshNode* nToKeep = *nIt;
5820 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5821 const SMDS_MeshNode* nToRemove = *nIt;
5822 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5823 if ( nToRemove != nToKeep ) {
5824 rmNodeIds.push_back( nToRemove->GetID() );
5825 AddToSameGroups( nToKeep, nToRemove, aMesh );
5828 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5829 while ( invElemIt->more() ) {
5830 const SMDS_MeshElement* elem = invElemIt->next();
5835 // Change element nodes or remove an element
5837 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5838 for ( ; eIt != elems.end(); eIt++ ) {
5839 const SMDS_MeshElement* elem = *eIt;
5840 int nbNodes = elem->NbNodes();
5841 int aShapeId = FindShape( elem );
5843 set<const SMDS_MeshNode*> nodeSet;
5844 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5845 int iUnique = 0, iCur = 0, nbRepl = 0;
5846 vector<int> iRepl( nbNodes );
5848 // get new seq of nodes
5849 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5850 while ( itN->more() ) {
5851 const SMDS_MeshNode* n =
5852 static_cast<const SMDS_MeshNode*>( itN->next() );
5854 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5855 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5857 // BUG 0020185: begin
5859 bool stopRecur = false;
5860 set<const SMDS_MeshNode*> nodesRecur;
5861 nodesRecur.insert(n);
5862 while (!stopRecur) {
5863 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5864 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5865 n = (*nnIt_i).second;
5866 if (!nodesRecur.insert(n).second) {
5867 // error: recursive dependancy
5876 iRepl[ nbRepl++ ] = iCur;
5878 curNodes[ iCur ] = n;
5879 bool isUnique = nodeSet.insert( n ).second;
5881 uniqueNodes[ iUnique++ ] = n;
5885 // Analyse element topology after replacement
5888 int nbUniqueNodes = nodeSet.size();
5889 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5890 // Polygons and Polyhedral volumes
5891 if (elem->IsPoly()) {
5893 if (elem->GetType() == SMDSAbs_Face) {
5895 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5897 for (; inode < nbNodes; inode++) {
5898 face_nodes[inode] = curNodes[inode];
5901 vector<const SMDS_MeshNode *> polygons_nodes;
5902 vector<int> quantities;
5903 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5907 for (int iface = 0; iface < nbNew - 1; iface++) {
5908 int nbNodes = quantities[iface];
5909 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5910 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5911 poly_nodes[ii] = polygons_nodes[inode];
5913 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5914 myLastCreatedElems.Append(newElem);
5916 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5918 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5921 rmElemIds.push_back(elem->GetID());
5925 else if (elem->GetType() == SMDSAbs_Volume) {
5926 // Polyhedral volume
5927 if (nbUniqueNodes < 4) {
5928 rmElemIds.push_back(elem->GetID());
5931 // each face has to be analized in order to check volume validity
5932 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5933 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5935 int nbFaces = aPolyedre->NbFaces();
5937 vector<const SMDS_MeshNode *> poly_nodes;
5938 vector<int> quantities;
5940 for (int iface = 1; iface <= nbFaces; iface++) {
5941 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5942 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5944 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5945 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5946 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5947 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5948 faceNode = (*nnIt).second;
5950 faceNodes[inode - 1] = faceNode;
5953 SimplifyFace(faceNodes, poly_nodes, quantities);
5956 if (quantities.size() > 3) {
5957 // to be done: remove coincident faces
5960 if (quantities.size() > 3)
5961 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5963 rmElemIds.push_back(elem->GetID());
5967 rmElemIds.push_back(elem->GetID());
5978 switch ( nbNodes ) {
5979 case 2: ///////////////////////////////////// EDGE
5980 isOk = false; break;
5981 case 3: ///////////////////////////////////// TRIANGLE
5982 isOk = false; break;
5984 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5986 else { //////////////////////////////////// QUADRANGLE
5987 if ( nbUniqueNodes < 3 )
5989 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5990 isOk = false; // opposite nodes stick
5993 case 6: ///////////////////////////////////// PENTAHEDRON
5994 if ( nbUniqueNodes == 4 ) {
5995 // ---------------------------------> tetrahedron
5997 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5998 // all top nodes stick: reverse a bottom
5999 uniqueNodes[ 0 ] = curNodes [ 1 ];
6000 uniqueNodes[ 1 ] = curNodes [ 0 ];
6002 else if (nbRepl == 3 &&
6003 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6004 // all bottom nodes stick: set a top before
6005 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6006 uniqueNodes[ 0 ] = curNodes [ 3 ];
6007 uniqueNodes[ 1 ] = curNodes [ 4 ];
6008 uniqueNodes[ 2 ] = curNodes [ 5 ];
6010 else if (nbRepl == 4 &&
6011 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6012 // a lateral face turns into a line: reverse a bottom
6013 uniqueNodes[ 0 ] = curNodes [ 1 ];
6014 uniqueNodes[ 1 ] = curNodes [ 0 ];
6019 else if ( nbUniqueNodes == 5 ) {
6020 // PENTAHEDRON --------------------> 2 tetrahedrons
6021 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6022 // a bottom node sticks with a linked top one
6024 SMDS_MeshElement* newElem =
6025 aMesh->AddVolume(curNodes[ 3 ],
6028 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6029 myLastCreatedElems.Append(newElem);
6031 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6032 // 2. : reverse a bottom
6033 uniqueNodes[ 0 ] = curNodes [ 1 ];
6034 uniqueNodes[ 1 ] = curNodes [ 0 ];
6044 if(elem->IsQuadratic()) { // Quadratic quadrangle
6057 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6058 uniqueNodes[0] = curNodes[0];
6059 uniqueNodes[1] = curNodes[2];
6060 uniqueNodes[2] = curNodes[3];
6061 uniqueNodes[3] = curNodes[5];
6062 uniqueNodes[4] = curNodes[6];
6063 uniqueNodes[5] = curNodes[7];
6066 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6067 uniqueNodes[0] = curNodes[0];
6068 uniqueNodes[1] = curNodes[1];
6069 uniqueNodes[2] = curNodes[2];
6070 uniqueNodes[3] = curNodes[4];
6071 uniqueNodes[4] = curNodes[5];
6072 uniqueNodes[5] = curNodes[6];
6075 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6076 uniqueNodes[0] = curNodes[1];
6077 uniqueNodes[1] = curNodes[2];
6078 uniqueNodes[2] = curNodes[3];
6079 uniqueNodes[3] = curNodes[5];
6080 uniqueNodes[4] = curNodes[6];
6081 uniqueNodes[5] = curNodes[0];
6084 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6085 uniqueNodes[0] = curNodes[0];
6086 uniqueNodes[1] = curNodes[1];
6087 uniqueNodes[2] = curNodes[3];
6088 uniqueNodes[3] = curNodes[4];
6089 uniqueNodes[4] = curNodes[6];
6090 uniqueNodes[5] = curNodes[7];
6093 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6094 uniqueNodes[0] = curNodes[0];
6095 uniqueNodes[1] = curNodes[2];
6096 uniqueNodes[2] = curNodes[3];
6097 uniqueNodes[3] = curNodes[1];
6098 uniqueNodes[4] = curNodes[6];
6099 uniqueNodes[5] = curNodes[7];
6102 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6103 uniqueNodes[0] = curNodes[0];
6104 uniqueNodes[1] = curNodes[1];
6105 uniqueNodes[2] = curNodes[2];
6106 uniqueNodes[3] = curNodes[4];
6107 uniqueNodes[4] = curNodes[5];
6108 uniqueNodes[5] = curNodes[7];
6111 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6112 uniqueNodes[0] = curNodes[0];
6113 uniqueNodes[1] = curNodes[1];
6114 uniqueNodes[2] = curNodes[3];
6115 uniqueNodes[3] = curNodes[4];
6116 uniqueNodes[4] = curNodes[2];
6117 uniqueNodes[5] = curNodes[7];
6120 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6121 uniqueNodes[0] = curNodes[0];
6122 uniqueNodes[1] = curNodes[1];
6123 uniqueNodes[2] = curNodes[2];
6124 uniqueNodes[3] = curNodes[4];
6125 uniqueNodes[4] = curNodes[5];
6126 uniqueNodes[5] = curNodes[3];
6132 //////////////////////////////////// HEXAHEDRON
6134 SMDS_VolumeTool hexa (elem);
6135 hexa.SetExternalNormal();
6136 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6137 //////////////////////// ---> tetrahedron
6138 for ( int iFace = 0; iFace < 6; iFace++ ) {
6139 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6140 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6141 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6142 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6143 // one face turns into a point ...
6144 int iOppFace = hexa.GetOppFaceIndex( iFace );
6145 ind = hexa.GetFaceNodesIndices( iOppFace );
6147 iUnique = 2; // reverse a tetrahedron bottom
6148 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6149 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6151 else if ( iUnique >= 0 )
6152 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6154 if ( nbStick == 1 ) {
6155 // ... and the opposite one - into a triangle.
6157 ind = hexa.GetFaceNodesIndices( iFace );
6158 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6165 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6166 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6167 for ( int iFace = 0; iFace < 6; iFace++ ) {
6168 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6169 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6170 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6171 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6172 // one face turns into a point ...
6173 int iOppFace = hexa.GetOppFaceIndex( iFace );
6174 ind = hexa.GetFaceNodesIndices( iOppFace );
6176 iUnique = 2; // reverse a tetrahedron 1 bottom
6177 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6178 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6180 else if ( iUnique >= 0 )
6181 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6183 if ( nbStick == 0 ) {
6184 // ... and the opposite one is a quadrangle
6186 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6187 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6190 SMDS_MeshElement* newElem =
6191 aMesh->AddVolume(curNodes[ind[ 0 ]],
6194 curNodes[indTop[ 0 ]]);
6195 myLastCreatedElems.Append(newElem);
6197 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6204 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6205 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6206 // find indices of quad and tri faces
6207 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6208 for ( iFace = 0; iFace < 6; iFace++ ) {
6209 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6211 for ( iCur = 0; iCur < 4; iCur++ )
6212 nodeSet.insert( curNodes[ind[ iCur ]] );
6213 nbUniqueNodes = nodeSet.size();
6214 if ( nbUniqueNodes == 3 )
6215 iTriFace[ nbTri++ ] = iFace;
6216 else if ( nbUniqueNodes == 4 )
6217 iQuadFace[ nbQuad++ ] = iFace;
6219 if (nbQuad == 2 && nbTri == 4 &&
6220 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6221 // 2 opposite quadrangles stuck with a diagonal;
6222 // sample groups of merged indices: (0-4)(2-6)
6223 // --------------------------------------------> 2 tetrahedrons
6224 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6225 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6226 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6227 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6228 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6229 // stuck with 0-2 diagonal
6237 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6238 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6239 // stuck with 1-3 diagonal
6251 uniqueNodes[ 0 ] = curNodes [ i0 ];
6252 uniqueNodes[ 1 ] = curNodes [ i1d ];
6253 uniqueNodes[ 2 ] = curNodes [ i3d ];
6254 uniqueNodes[ 3 ] = curNodes [ i0t ];
6257 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6261 myLastCreatedElems.Append(newElem);
6263 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6266 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6267 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6268 // --------------------------------------------> prism
6269 // find 2 opposite triangles
6271 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6272 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6273 // find indices of kept and replaced nodes
6274 // and fill unique nodes of 2 opposite triangles
6275 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6276 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6277 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6278 // fill unique nodes
6281 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6282 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
6283 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6285 // iCur of a linked node of the opposite face (make normals co-directed):
6286 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6287 // check that correspondent corners of triangles are linked
6288 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6291 uniqueNodes[ iUnique ] = n;
6292 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6301 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6307 } // switch ( nbNodes )
6309 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6312 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
6313 // Change nodes of polyedre
6314 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6315 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6317 int nbFaces = aPolyedre->NbFaces();
6319 vector<const SMDS_MeshNode *> poly_nodes;
6320 vector<int> quantities (nbFaces);
6322 for (int iface = 1; iface <= nbFaces; iface++) {
6323 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6324 quantities[iface - 1] = nbFaceNodes;
6326 for (inode = 1; inode <= nbFaceNodes; inode++) {
6327 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6329 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6330 if (nnIt != nodeNodeMap.end()) { // curNode sticks
6331 curNode = (*nnIt).second;
6333 poly_nodes.push_back(curNode);
6336 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6340 // Change regular element or polygon
6341 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
6345 // Remove invalid regular element or invalid polygon
6346 rmElemIds.push_back( elem->GetID() );
6349 } // loop on elements
6351 // Remove equal nodes and bad elements
6353 Remove( rmNodeIds, true );
6354 Remove( rmElemIds, false );
6359 // ========================================================
6360 // class : SortableElement
6361 // purpose : allow sorting elements basing on their nodes
6362 // ========================================================
6363 class SortableElement : public set <const SMDS_MeshElement*>
6367 SortableElement( const SMDS_MeshElement* theElem )
6370 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6371 while ( nodeIt->more() )
6372 this->insert( nodeIt->next() );
6375 const SMDS_MeshElement* Get() const
6378 void Set(const SMDS_MeshElement* e) const
6383 mutable const SMDS_MeshElement* myElem;
6386 //=======================================================================
6387 //function : FindEqualElements
6388 //purpose : Return list of group of elements built on the same nodes.
6389 // Search among theElements or in the whole mesh if theElements is empty
6390 //=======================================================================
6391 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
6392 TListOfListOfElementsID & theGroupsOfElementsID)
6394 myLastCreatedElems.Clear();
6395 myLastCreatedNodes.Clear();
6397 typedef set<const SMDS_MeshElement*> TElemsSet;
6398 typedef map< SortableElement, int > TMapOfNodeSet;
6399 typedef list<int> TGroupOfElems;
6402 if ( theElements.empty() )
6403 { // get all elements in the mesh
6404 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
6405 while ( eIt->more() )
6406 elems.insert( elems.end(), eIt->next());
6409 elems = theElements;
6411 vector< TGroupOfElems > arrayOfGroups;
6412 TGroupOfElems groupOfElems;
6413 TMapOfNodeSet mapOfNodeSet;
6415 TElemsSet::iterator elemIt = elems.begin();
6416 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
6417 const SMDS_MeshElement* curElem = *elemIt;
6418 SortableElement SE(curElem);
6421 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
6422 if( !(pp.second) ) {
6423 TMapOfNodeSet::iterator& itSE = pp.first;
6424 ind = (*itSE).second;
6425 arrayOfGroups[ind].push_back(curElem->GetID());
6428 groupOfElems.clear();
6429 groupOfElems.push_back(curElem->GetID());
6430 arrayOfGroups.push_back(groupOfElems);
6435 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
6436 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
6437 groupOfElems = *groupIt;
6438 if ( groupOfElems.size() > 1 ) {
6439 groupOfElems.sort();
6440 theGroupsOfElementsID.push_back(groupOfElems);
6445 //=======================================================================
6446 //function : MergeElements
6447 //purpose : In each given group, substitute all elements by the first one.
6448 //=======================================================================
6450 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
6452 myLastCreatedElems.Clear();
6453 myLastCreatedNodes.Clear();
6455 typedef list<int> TListOfIDs;
6456 TListOfIDs rmElemIds; // IDs of elems to remove
6458 SMESHDS_Mesh* aMesh = GetMeshDS();
6460 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
6461 while ( groupsIt != theGroupsOfElementsID.end() ) {
6462 TListOfIDs& aGroupOfElemID = *groupsIt;
6463 aGroupOfElemID.sort();
6464 int elemIDToKeep = aGroupOfElemID.front();
6465 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
6466 aGroupOfElemID.pop_front();
6467 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
6468 while ( idIt != aGroupOfElemID.end() ) {
6469 int elemIDToRemove = *idIt;
6470 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
6471 // add the kept element in groups of removed one (PAL15188)
6472 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
6473 rmElemIds.push_back( elemIDToRemove );
6479 Remove( rmElemIds, false );
6482 //=======================================================================
6483 //function : MergeEqualElements
6484 //purpose : Remove all but one of elements built on the same nodes.
6485 //=======================================================================
6487 void SMESH_MeshEditor::MergeEqualElements()
6489 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
6490 to merge equal elements in the whole mesh */
6491 TListOfListOfElementsID aGroupsOfElementsID;
6492 FindEqualElements(aMeshElements, aGroupsOfElementsID);
6493 MergeElements(aGroupsOfElementsID);
6496 //=======================================================================
6497 //function : FindFaceInSet
6498 //purpose : Return a face having linked nodes n1 and n2 and which is
6499 // - not in avoidSet,
6500 // - in elemSet provided that !elemSet.empty()
6501 //=======================================================================
6503 const SMDS_MeshElement*
6504 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
6505 const SMDS_MeshNode* n2,
6506 const TIDSortedElemSet& elemSet,
6507 const TIDSortedElemSet& avoidSet)
6510 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
6511 while ( invElemIt->more() ) { // loop on inverse elements of n1
6512 const SMDS_MeshElement* elem = invElemIt->next();
6513 if (avoidSet.find( elem ) != avoidSet.end() )
6515 if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
6517 // get face nodes and find index of n1
6518 int i1, nbN = elem->NbNodes(), iNode = 0;
6519 //const SMDS_MeshNode* faceNodes[ nbN ], *n;
6520 vector<const SMDS_MeshNode*> faceNodes( nbN );
6521 const SMDS_MeshNode* n;
6522 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6523 while ( nIt->more() ) {
6524 faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6525 if ( faceNodes[ iNode++ ] == n1 )
6528 // find a n2 linked to n1
6529 if(!elem->IsQuadratic()) {
6530 for ( iNode = 0; iNode < 2; iNode++ ) {
6531 if ( iNode ) // node before n1
6532 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6533 else // node after n1
6534 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6539 else { // analysis for quadratic elements
6540 bool IsFind = false;
6541 // check using only corner nodes
6542 for ( iNode = 0; iNode < 2; iNode++ ) {
6543 if ( iNode ) // node before n1
6544 n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
6545 else // node after n1
6546 n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
6554 // check using all nodes
6555 const SMDS_QuadraticFaceOfNodes* F =
6556 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6557 // use special nodes iterator
6559 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6560 while ( anIter->more() ) {
6561 faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
6562 if ( faceNodes[ iNode++ ] == n1 )
6565 for ( iNode = 0; iNode < 2; iNode++ ) {
6566 if ( iNode ) // node before n1
6567 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6568 else // node after n1
6569 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6575 } // end analysis for quadratic elements
6580 //=======================================================================
6581 //function : findAdjacentFace
6583 //=======================================================================
6585 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6586 const SMDS_MeshNode* n2,
6587 const SMDS_MeshElement* elem)
6589 TIDSortedElemSet elemSet, avoidSet;
6591 avoidSet.insert ( elem );
6592 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6595 //=======================================================================
6596 //function : FindFreeBorder
6598 //=======================================================================
6600 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6602 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
6603 const SMDS_MeshNode* theSecondNode,
6604 const SMDS_MeshNode* theLastNode,
6605 list< const SMDS_MeshNode* > & theNodes,
6606 list< const SMDS_MeshElement* >& theFaces)
6608 if ( !theFirstNode || !theSecondNode )
6610 // find border face between theFirstNode and theSecondNode
6611 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6615 theFaces.push_back( curElem );
6616 theNodes.push_back( theFirstNode );
6617 theNodes.push_back( theSecondNode );
6619 //vector<const SMDS_MeshNode*> nodes;
6620 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6621 TIDSortedElemSet foundElems;
6622 bool needTheLast = ( theLastNode != 0 );
6624 while ( nStart != theLastNode ) {
6625 if ( nStart == theFirstNode )
6626 return !needTheLast;
6628 // find all free border faces sharing form nStart
6630 list< const SMDS_MeshElement* > curElemList;
6631 list< const SMDS_MeshNode* > nStartList;
6632 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6633 while ( invElemIt->more() ) {
6634 const SMDS_MeshElement* e = invElemIt->next();
6635 if ( e == curElem || foundElems.insert( e ).second ) {
6637 int iNode = 0, nbNodes = e->NbNodes();
6638 //const SMDS_MeshNode* nodes[nbNodes+1];
6639 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6641 if(e->IsQuadratic()) {
6642 const SMDS_QuadraticFaceOfNodes* F =
6643 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6644 // use special nodes iterator
6645 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6646 while( anIter->more() ) {
6647 nodes[ iNode++ ] = anIter->next();
6651 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6652 while ( nIt->more() )
6653 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6655 nodes[ iNode ] = nodes[ 0 ];
6657 for ( iNode = 0; iNode < nbNodes; iNode++ )
6658 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6659 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6660 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6662 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6663 curElemList.push_back( e );
6667 // analyse the found
6669 int nbNewBorders = curElemList.size();
6670 if ( nbNewBorders == 0 ) {
6671 // no free border furthermore
6672 return !needTheLast;
6674 else if ( nbNewBorders == 1 ) {
6675 // one more element found
6677 nStart = nStartList.front();
6678 curElem = curElemList.front();
6679 theFaces.push_back( curElem );
6680 theNodes.push_back( nStart );
6683 // several continuations found
6684 list< const SMDS_MeshElement* >::iterator curElemIt;
6685 list< const SMDS_MeshNode* >::iterator nStartIt;
6686 // check if one of them reached the last node
6687 if ( needTheLast ) {
6688 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6689 curElemIt!= curElemList.end();
6690 curElemIt++, nStartIt++ )
6691 if ( *nStartIt == theLastNode ) {
6692 theFaces.push_back( *curElemIt );
6693 theNodes.push_back( *nStartIt );
6697 // find the best free border by the continuations
6698 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6699 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6700 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6701 curElemIt!= curElemList.end();
6702 curElemIt++, nStartIt++ )
6704 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6705 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6706 // find one more free border
6707 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6711 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6712 // choice: clear a worse one
6713 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6714 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6715 contNodes[ iWorse ].clear();
6716 contFaces[ iWorse ].clear();
6719 if ( contNodes[0].empty() && contNodes[1].empty() )
6722 // append the best free border
6723 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6724 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6725 theNodes.pop_back(); // remove nIgnore
6726 theNodes.pop_back(); // remove nStart
6727 theFaces.pop_back(); // remove curElem
6728 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6729 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6730 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6731 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6734 } // several continuations found
6735 } // while ( nStart != theLastNode )
6740 //=======================================================================
6741 //function : CheckFreeBorderNodes
6742 //purpose : Return true if the tree nodes are on a free border
6743 //=======================================================================
6745 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6746 const SMDS_MeshNode* theNode2,
6747 const SMDS_MeshNode* theNode3)
6749 list< const SMDS_MeshNode* > nodes;
6750 list< const SMDS_MeshElement* > faces;
6751 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6754 //=======================================================================
6755 //function : SewFreeBorder
6757 //=======================================================================
6759 SMESH_MeshEditor::Sew_Error
6760 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6761 const SMDS_MeshNode* theBordSecondNode,
6762 const SMDS_MeshNode* theBordLastNode,
6763 const SMDS_MeshNode* theSideFirstNode,
6764 const SMDS_MeshNode* theSideSecondNode,
6765 const SMDS_MeshNode* theSideThirdNode,
6766 const bool theSideIsFreeBorder,
6767 const bool toCreatePolygons,
6768 const bool toCreatePolyedrs)
6770 myLastCreatedElems.Clear();
6771 myLastCreatedNodes.Clear();
6773 MESSAGE("::SewFreeBorder()");
6774 Sew_Error aResult = SEW_OK;
6776 // ====================================
6777 // find side nodes and elements
6778 // ====================================
6780 list< const SMDS_MeshNode* > nSide[ 2 ];
6781 list< const SMDS_MeshElement* > eSide[ 2 ];
6782 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6783 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6787 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6788 nSide[0], eSide[0])) {
6789 MESSAGE(" Free Border 1 not found " );
6790 aResult = SEW_BORDER1_NOT_FOUND;
6792 if (theSideIsFreeBorder) {
6795 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6796 nSide[1], eSide[1])) {
6797 MESSAGE(" Free Border 2 not found " );
6798 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6801 if ( aResult != SEW_OK )
6804 if (!theSideIsFreeBorder) {
6808 // -------------------------------------------------------------------------
6810 // 1. If nodes to merge are not coincident, move nodes of the free border
6811 // from the coord sys defined by the direction from the first to last
6812 // nodes of the border to the correspondent sys of the side 2
6813 // 2. On the side 2, find the links most co-directed with the correspondent
6814 // links of the free border
6815 // -------------------------------------------------------------------------
6817 // 1. Since sewing may brake if there are volumes to split on the side 2,
6818 // we wont move nodes but just compute new coordinates for them
6819 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6820 TNodeXYZMap nBordXYZ;
6821 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6822 list< const SMDS_MeshNode* >::iterator nBordIt;
6824 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6825 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6826 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6827 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6828 double tol2 = 1.e-8;
6829 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6830 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6831 // Need node movement.
6833 // find X and Z axes to create trsf
6834 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6836 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6838 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6841 gp_Ax3 toBordAx( Pb1, Zb, X );
6842 gp_Ax3 fromSideAx( Ps1, Zs, X );
6843 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6845 gp_Trsf toBordSys, fromSide2Sys;
6846 toBordSys.SetTransformation( toBordAx );
6847 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6848 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6851 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6852 const SMDS_MeshNode* n = *nBordIt;
6853 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6854 toBordSys.Transforms( xyz );
6855 fromSide2Sys.Transforms( xyz );
6856 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6860 // just insert nodes XYZ in the nBordXYZ map
6861 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6862 const SMDS_MeshNode* n = *nBordIt;
6863 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6867 // 2. On the side 2, find the links most co-directed with the correspondent
6868 // links of the free border
6870 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6871 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6872 sideNodes.push_back( theSideFirstNode );
6874 bool hasVolumes = false;
6875 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6876 set<long> foundSideLinkIDs, checkedLinkIDs;
6877 SMDS_VolumeTool volume;
6878 //const SMDS_MeshNode* faceNodes[ 4 ];
6880 const SMDS_MeshNode* sideNode;
6881 const SMDS_MeshElement* sideElem;
6882 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6883 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6884 nBordIt = bordNodes.begin();
6886 // border node position and border link direction to compare with
6887 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6888 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6889 // choose next side node by link direction or by closeness to
6890 // the current border node:
6891 bool searchByDir = ( *nBordIt != theBordLastNode );
6893 // find the next node on the Side 2
6895 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6897 checkedLinkIDs.clear();
6898 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6900 // loop on inverse elements of current node (prevSideNode) on the Side 2
6901 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6902 while ( invElemIt->more() )
6904 const SMDS_MeshElement* elem = invElemIt->next();
6905 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6906 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6907 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6908 bool isVolume = volume.Set( elem );
6909 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6910 if ( isVolume ) // --volume
6912 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6913 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6914 if(elem->IsQuadratic()) {
6915 const SMDS_QuadraticFaceOfNodes* F =
6916 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6917 // use special nodes iterator
6918 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6919 while( anIter->more() ) {
6920 nodes[ iNode ] = anIter->next();
6921 if ( nodes[ iNode++ ] == prevSideNode )
6922 iPrevNode = iNode - 1;
6926 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6927 while ( nIt->more() ) {
6928 nodes[ iNode ] = cast2Node( nIt->next() );
6929 if ( nodes[ iNode++ ] == prevSideNode )
6930 iPrevNode = iNode - 1;
6933 // there are 2 links to check
6938 // loop on links, to be precise, on the second node of links
6939 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6940 const SMDS_MeshNode* n = nodes[ iNode ];
6942 if ( !volume.IsLinked( n, prevSideNode ))
6946 if ( iNode ) // a node before prevSideNode
6947 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6948 else // a node after prevSideNode
6949 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6951 // check if this link was already used
6952 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6953 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6954 if (!isJustChecked &&
6955 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6957 // test a link geometrically
6958 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6959 bool linkIsBetter = false;
6960 double dot = 0.0, dist = 0.0;
6961 if ( searchByDir ) { // choose most co-directed link
6962 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6963 linkIsBetter = ( dot > maxDot );
6965 else { // choose link with the node closest to bordPos
6966 dist = ( nextXYZ - bordPos ).SquareModulus();
6967 linkIsBetter = ( dist < minDist );
6969 if ( linkIsBetter ) {
6978 } // loop on inverse elements of prevSideNode
6981 MESSAGE(" Cant find path by links of the Side 2 ");
6982 return SEW_BAD_SIDE_NODES;
6984 sideNodes.push_back( sideNode );
6985 sideElems.push_back( sideElem );
6986 foundSideLinkIDs.insert ( linkID );
6987 prevSideNode = sideNode;
6989 if ( *nBordIt == theBordLastNode )
6990 searchByDir = false;
6992 // find the next border link to compare with
6993 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6994 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6995 // move to next border node if sideNode is before forward border node (bordPos)
6996 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6997 prevBordNode = *nBordIt;
6999 bordPos = nBordXYZ[ *nBordIt ];
7000 bordDir = bordPos - nBordXYZ[ prevBordNode ];
7001 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7005 while ( sideNode != theSideSecondNode );
7007 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7008 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7009 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7011 } // end nodes search on the side 2
7013 // ============================
7014 // sew the border to the side 2
7015 // ============================
7017 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
7018 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7020 TListOfListOfNodes nodeGroupsToMerge;
7021 if ( nbNodes[0] == nbNodes[1] ||
7022 ( theSideIsFreeBorder && !theSideThirdNode)) {
7024 // all nodes are to be merged
7026 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7027 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7028 nIt[0]++, nIt[1]++ )
7030 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7031 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7032 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7037 // insert new nodes into the border and the side to get equal nb of segments
7039 // get normalized parameters of nodes on the borders
7040 //double param[ 2 ][ maxNbNodes ];
7042 param[0] = new double [ maxNbNodes ];
7043 param[1] = new double [ maxNbNodes ];
7045 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7046 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7047 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7048 const SMDS_MeshNode* nPrev = *nIt;
7049 double bordLength = 0;
7050 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7051 const SMDS_MeshNode* nCur = *nIt;
7052 gp_XYZ segment (nCur->X() - nPrev->X(),
7053 nCur->Y() - nPrev->Y(),
7054 nCur->Z() - nPrev->Z());
7055 double segmentLen = segment.Modulus();
7056 bordLength += segmentLen;
7057 param[ iBord ][ iNode ] = bordLength;
7060 // normalize within [0,1]
7061 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7062 param[ iBord ][ iNode ] /= bordLength;
7066 // loop on border segments
7067 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7068 int i[ 2 ] = { 0, 0 };
7069 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7070 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7072 TElemOfNodeListMap insertMap;
7073 TElemOfNodeListMap::iterator insertMapIt;
7075 // key: elem to insert nodes into
7076 // value: 2 nodes to insert between + nodes to be inserted
7078 bool next[ 2 ] = { false, false };
7080 // find min adjacent segment length after sewing
7081 double nextParam = 10., prevParam = 0;
7082 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7083 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7084 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7085 if ( i[ iBord ] > 0 )
7086 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7088 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7089 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7090 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7092 // choose to insert or to merge nodes
7093 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7094 if ( Abs( du ) <= minSegLen * 0.2 ) {
7097 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7098 const SMDS_MeshNode* n0 = *nIt[0];
7099 const SMDS_MeshNode* n1 = *nIt[1];
7100 nodeGroupsToMerge.back().push_back( n1 );
7101 nodeGroupsToMerge.back().push_back( n0 );
7102 // position of node of the border changes due to merge
7103 param[ 0 ][ i[0] ] += du;
7104 // move n1 for the sake of elem shape evaluation during insertion.
7105 // n1 will be removed by MergeNodes() anyway
7106 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7107 next[0] = next[1] = true;
7112 int intoBord = ( du < 0 ) ? 0 : 1;
7113 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7114 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7115 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7116 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7117 if ( intoBord == 1 ) {
7118 // move node of the border to be on a link of elem of the side
7119 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7120 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7121 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7122 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7123 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7125 insertMapIt = insertMap.find( elem );
7126 bool notFound = ( insertMapIt == insertMap.end() );
7127 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7129 // insert into another link of the same element:
7130 // 1. perform insertion into the other link of the elem
7131 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7132 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7133 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7134 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7135 // 2. perform insertion into the link of adjacent faces
7137 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7139 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7143 if (toCreatePolyedrs) {
7144 // perform insertion into the links of adjacent volumes
7145 UpdateVolumes(n12, n22, nodeList);
7147 // 3. find an element appeared on n1 and n2 after the insertion
7148 insertMap.erase( elem );
7149 elem = findAdjacentFace( n1, n2, 0 );
7151 if ( notFound || otherLink ) {
7152 // add element and nodes of the side into the insertMap
7153 insertMapIt = insertMap.insert
7154 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7155 (*insertMapIt).second.push_back( n1 );
7156 (*insertMapIt).second.push_back( n2 );
7158 // add node to be inserted into elem
7159 (*insertMapIt).second.push_back( nIns );
7160 next[ 1 - intoBord ] = true;
7163 // go to the next segment
7164 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7165 if ( next[ iBord ] ) {
7166 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7168 nPrev[ iBord ] = *nIt[ iBord ];
7169 nIt[ iBord ]++; i[ iBord ]++;
7173 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7175 // perform insertion of nodes into elements
7177 for (insertMapIt = insertMap.begin();
7178 insertMapIt != insertMap.end();
7181 const SMDS_MeshElement* elem = (*insertMapIt).first;
7182 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7183 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7184 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7186 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7188 if ( !theSideIsFreeBorder ) {
7189 // look for and insert nodes into the faces adjacent to elem
7191 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7193 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7198 if (toCreatePolyedrs) {
7199 // perform insertion into the links of adjacent volumes
7200 UpdateVolumes(n1, n2, nodeList);
7206 } // end: insert new nodes
7208 MergeNodes ( nodeGroupsToMerge );
7213 //=======================================================================
7214 //function : InsertNodesIntoLink
7215 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7216 // and theBetweenNode2 and split theElement
7217 //=======================================================================
7219 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7220 const SMDS_MeshNode* theBetweenNode1,
7221 const SMDS_MeshNode* theBetweenNode2,
7222 list<const SMDS_MeshNode*>& theNodesToInsert,
7223 const bool toCreatePoly)
7225 if ( theFace->GetType() != SMDSAbs_Face ) return;
7227 // find indices of 2 link nodes and of the rest nodes
7228 int iNode = 0, il1, il2, i3, i4;
7229 il1 = il2 = i3 = i4 = -1;
7230 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7231 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7233 if(theFace->IsQuadratic()) {
7234 const SMDS_QuadraticFaceOfNodes* F =
7235 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7236 // use special nodes iterator
7237 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7238 while( anIter->more() ) {
7239 const SMDS_MeshNode* n = anIter->next();
7240 if ( n == theBetweenNode1 )
7242 else if ( n == theBetweenNode2 )
7248 nodes[ iNode++ ] = n;
7252 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7253 while ( nodeIt->more() ) {
7254 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7255 if ( n == theBetweenNode1 )
7257 else if ( n == theBetweenNode2 )
7263 nodes[ iNode++ ] = n;
7266 if ( il1 < 0 || il2 < 0 || i3 < 0 )
7269 // arrange link nodes to go one after another regarding the face orientation
7270 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7271 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7276 aNodesToInsert.reverse();
7278 // check that not link nodes of a quadrangles are in good order
7279 int nbFaceNodes = theFace->NbNodes();
7280 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7286 if (toCreatePoly || theFace->IsPoly()) {
7289 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7291 // add nodes of face up to first node of link
7294 if(theFace->IsQuadratic()) {
7295 const SMDS_QuadraticFaceOfNodes* F =
7296 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7297 // use special nodes iterator
7298 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7299 while( anIter->more() && !isFLN ) {
7300 const SMDS_MeshNode* n = anIter->next();
7301 poly_nodes[iNode++] = n;
7302 if (n == nodes[il1]) {
7306 // add nodes to insert
7307 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7308 for (; nIt != aNodesToInsert.end(); nIt++) {
7309 poly_nodes[iNode++] = *nIt;
7311 // add nodes of face starting from last node of link
7312 while ( anIter->more() ) {
7313 poly_nodes[iNode++] = anIter->next();
7317 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7318 while ( nodeIt->more() && !isFLN ) {
7319 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7320 poly_nodes[iNode++] = n;
7321 if (n == nodes[il1]) {
7325 // add nodes to insert
7326 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7327 for (; nIt != aNodesToInsert.end(); nIt++) {
7328 poly_nodes[iNode++] = *nIt;
7330 // add nodes of face starting from last node of link
7331 while ( nodeIt->more() ) {
7332 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7333 poly_nodes[iNode++] = n;
7337 // edit or replace the face
7338 SMESHDS_Mesh *aMesh = GetMeshDS();
7340 if (theFace->IsPoly()) {
7341 aMesh->ChangePolygonNodes(theFace, poly_nodes);
7344 int aShapeId = FindShape( theFace );
7346 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7347 myLastCreatedElems.Append(newElem);
7348 if ( aShapeId && newElem )
7349 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7351 aMesh->RemoveElement(theFace);
7356 if( !theFace->IsQuadratic() ) {
7358 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7359 int nbLinkNodes = 2 + aNodesToInsert.size();
7360 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7361 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7362 linkNodes[ 0 ] = nodes[ il1 ];
7363 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7364 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7365 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7366 linkNodes[ iNode++ ] = *nIt;
7368 // decide how to split a quadrangle: compare possible variants
7369 // and choose which of splits to be a quadrangle
7370 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7371 if ( nbFaceNodes == 3 ) {
7372 iBestQuad = nbSplits;
7375 else if ( nbFaceNodes == 4 ) {
7376 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7377 double aBestRate = DBL_MAX;
7378 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7380 double aBadRate = 0;
7381 // evaluate elements quality
7382 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7383 if ( iSplit == iQuad ) {
7384 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7388 aBadRate += getBadRate( &quad, aCrit );
7391 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7393 nodes[ iSplit < iQuad ? i4 : i3 ]);
7394 aBadRate += getBadRate( &tria, aCrit );
7398 if ( aBadRate < aBestRate ) {
7400 aBestRate = aBadRate;
7405 // create new elements
7406 SMESHDS_Mesh *aMesh = GetMeshDS();
7407 int aShapeId = FindShape( theFace );
7410 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7411 SMDS_MeshElement* newElem = 0;
7412 if ( iSplit == iBestQuad )
7413 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7418 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7420 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7421 myLastCreatedElems.Append(newElem);
7422 if ( aShapeId && newElem )
7423 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7426 // change nodes of theFace
7427 const SMDS_MeshNode* newNodes[ 4 ];
7428 newNodes[ 0 ] = linkNodes[ i1 ];
7429 newNodes[ 1 ] = linkNodes[ i2 ];
7430 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7431 newNodes[ 3 ] = nodes[ i4 ];
7432 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7433 } // end if(!theFace->IsQuadratic())
7434 else { // theFace is quadratic
7435 // we have to split theFace on simple triangles and one simple quadrangle
7437 int nbshift = tmp*2;
7438 // shift nodes in nodes[] by nbshift
7440 for(i=0; i<nbshift; i++) {
7441 const SMDS_MeshNode* n = nodes[0];
7442 for(j=0; j<nbFaceNodes-1; j++) {
7443 nodes[j] = nodes[j+1];
7445 nodes[nbFaceNodes-1] = n;
7447 il1 = il1 - nbshift;
7448 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7449 // n0 n1 n2 n0 n1 n2
7450 // +-----+-----+ +-----+-----+
7459 // create new elements
7460 SMESHDS_Mesh *aMesh = GetMeshDS();
7461 int aShapeId = FindShape( theFace );
7464 if(nbFaceNodes==6) { // quadratic triangle
7465 SMDS_MeshElement* newElem =
7466 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7467 myLastCreatedElems.Append(newElem);
7468 if ( aShapeId && newElem )
7469 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7470 if(theFace->IsMediumNode(nodes[il1])) {
7471 // create quadrangle
7472 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
7473 myLastCreatedElems.Append(newElem);
7474 if ( aShapeId && newElem )
7475 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7481 // create quadrangle
7482 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
7483 myLastCreatedElems.Append(newElem);
7484 if ( aShapeId && newElem )
7485 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7491 else { // nbFaceNodes==8 - quadratic quadrangle
7492 SMDS_MeshElement* newElem =
7493 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7494 myLastCreatedElems.Append(newElem);
7495 if ( aShapeId && newElem )
7496 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7497 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
7498 myLastCreatedElems.Append(newElem);
7499 if ( aShapeId && newElem )
7500 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7501 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
7502 myLastCreatedElems.Append(newElem);
7503 if ( aShapeId && newElem )
7504 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7505 if(theFace->IsMediumNode(nodes[il1])) {
7506 // create quadrangle
7507 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
7508 myLastCreatedElems.Append(newElem);
7509 if ( aShapeId && newElem )
7510 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7516 // create quadrangle
7517 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7518 myLastCreatedElems.Append(newElem);
7519 if ( aShapeId && newElem )
7520 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7526 // create needed triangles using n1,n2,n3 and inserted nodes
7527 int nbn = 2 + aNodesToInsert.size();
7528 //const SMDS_MeshNode* aNodes[nbn];
7529 vector<const SMDS_MeshNode*> aNodes(nbn);
7530 aNodes[0] = nodes[n1];
7531 aNodes[nbn-1] = nodes[n2];
7532 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7533 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7534 aNodes[iNode++] = *nIt;
7536 for(i=1; i<nbn; i++) {
7537 SMDS_MeshElement* newElem =
7538 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7539 myLastCreatedElems.Append(newElem);
7540 if ( aShapeId && newElem )
7541 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7543 // remove old quadratic face
7544 aMesh->RemoveElement(theFace);
7548 //=======================================================================
7549 //function : UpdateVolumes
7551 //=======================================================================
7552 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
7553 const SMDS_MeshNode* theBetweenNode2,
7554 list<const SMDS_MeshNode*>& theNodesToInsert)
7556 myLastCreatedElems.Clear();
7557 myLastCreatedNodes.Clear();
7559 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7560 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7561 const SMDS_MeshElement* elem = invElemIt->next();
7563 // check, if current volume has link theBetweenNode1 - theBetweenNode2
7564 SMDS_VolumeTool aVolume (elem);
7565 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7568 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7569 int iface, nbFaces = aVolume.NbFaces();
7570 vector<const SMDS_MeshNode *> poly_nodes;
7571 vector<int> quantities (nbFaces);
7573 for (iface = 0; iface < nbFaces; iface++) {
7574 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7575 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7576 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7578 for (int inode = 0; inode < nbFaceNodes; inode++) {
7579 poly_nodes.push_back(faceNodes[inode]);
7581 if (nbInserted == 0) {
7582 if (faceNodes[inode] == theBetweenNode1) {
7583 if (faceNodes[inode + 1] == theBetweenNode2) {
7584 nbInserted = theNodesToInsert.size();
7586 // add nodes to insert
7587 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7588 for (; nIt != theNodesToInsert.end(); nIt++) {
7589 poly_nodes.push_back(*nIt);
7593 else if (faceNodes[inode] == theBetweenNode2) {
7594 if (faceNodes[inode + 1] == theBetweenNode1) {
7595 nbInserted = theNodesToInsert.size();
7597 // add nodes to insert in reversed order
7598 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7600 for (; nIt != theNodesToInsert.begin(); nIt--) {
7601 poly_nodes.push_back(*nIt);
7603 poly_nodes.push_back(*nIt);
7610 quantities[iface] = nbFaceNodes + nbInserted;
7613 // Replace or update the volume
7614 SMESHDS_Mesh *aMesh = GetMeshDS();
7616 if (elem->IsPoly()) {
7617 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7621 int aShapeId = FindShape( elem );
7623 SMDS_MeshElement* newElem =
7624 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7625 myLastCreatedElems.Append(newElem);
7626 if (aShapeId && newElem)
7627 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7629 aMesh->RemoveElement(elem);
7634 //=======================================================================
7636 * \brief Convert elements contained in a submesh to quadratic
7637 * \retval int - nb of checked elements
7639 //=======================================================================
7641 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
7642 SMESH_MesherHelper& theHelper,
7643 const bool theForce3d)
7646 if( !theSm ) return nbElem;
7648 const bool notFromGroups = false;
7649 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7650 while(ElemItr->more())
7653 const SMDS_MeshElement* elem = ElemItr->next();
7654 if( !elem || elem->IsQuadratic() ) continue;
7656 int id = elem->GetID();
7657 int nbNodes = elem->NbNodes();
7658 vector<const SMDS_MeshNode *> aNds (nbNodes);
7660 for(int i = 0; i < nbNodes; i++)
7662 aNds[i] = elem->GetNode(i);
7664 SMDSAbs_ElementType aType = elem->GetType();
7666 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7668 const SMDS_MeshElement* NewElem = 0;
7674 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7682 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7685 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7692 case SMDSAbs_Volume :
7697 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7700 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
7703 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7706 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7707 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7717 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7719 theSm->AddElement( NewElem );
7724 //=======================================================================
7725 //function : ConvertToQuadratic
7727 //=======================================================================
7728 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7730 SMESHDS_Mesh* meshDS = GetMeshDS();
7732 SMESH_MesherHelper aHelper(*myMesh);
7733 aHelper.SetIsQuadratic( true );
7734 const bool notFromGroups = false;
7736 int nbCheckedElems = 0;
7737 if ( myMesh->HasShapeToMesh() )
7739 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7741 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7742 while ( smIt->more() ) {
7743 SMESH_subMesh* sm = smIt->next();
7744 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7745 aHelper.SetSubShape( sm->GetSubShape() );
7746 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7751 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7752 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7754 SMESHDS_SubMesh *smDS = 0;
7755 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7756 while(aEdgeItr->more())
7758 const SMDS_MeshEdge* edge = aEdgeItr->next();
7759 if(edge && !edge->IsQuadratic())
7761 int id = edge->GetID();
7762 const SMDS_MeshNode* n1 = edge->GetNode(0);
7763 const SMDS_MeshNode* n2 = edge->GetNode(1);
7765 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7767 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7768 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7771 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7772 while(aFaceItr->more())
7774 const SMDS_MeshFace* face = aFaceItr->next();
7775 if(!face || face->IsQuadratic() ) continue;
7777 int id = face->GetID();
7778 int nbNodes = face->NbNodes();
7779 vector<const SMDS_MeshNode *> aNds (nbNodes);
7781 for(int i = 0; i < nbNodes; i++)
7783 aNds[i] = face->GetNode(i);
7786 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7788 SMDS_MeshFace * NewFace = 0;
7792 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7795 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7800 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7802 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7803 while(aVolumeItr->more())
7805 const SMDS_MeshVolume* volume = aVolumeItr->next();
7806 if(!volume || volume->IsQuadratic() ) continue;
7808 int id = volume->GetID();
7809 int nbNodes = volume->NbNodes();
7810 vector<const SMDS_MeshNode *> aNds (nbNodes);
7812 for(int i = 0; i < nbNodes; i++)
7814 aNds[i] = volume->GetNode(i);
7817 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7819 SMDS_MeshVolume * NewVolume = 0;
7823 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7824 aNds[3], id, theForce3d );
7827 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7828 aNds[3], aNds[4], id, theForce3d);
7831 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7832 aNds[3], aNds[4], aNds[5], id, theForce3d);
7835 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7836 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7841 ReplaceElemInGroups(volume, NewVolume, meshDS);
7844 if ( !theForce3d ) {
7845 aHelper.SetSubShape(0); // apply to the whole mesh
7846 aHelper.FixQuadraticElements();
7850 //=======================================================================
7852 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7853 * \retval int - nb of checked elements
7855 //=======================================================================
7857 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7858 SMDS_ElemIteratorPtr theItr,
7859 const int theShapeID)
7862 SMESHDS_Mesh* meshDS = GetMeshDS();
7863 const bool notFromGroups = false;
7865 while( theItr->more() )
7867 const SMDS_MeshElement* elem = theItr->next();
7869 if( elem && elem->IsQuadratic())
7871 int id = elem->GetID();
7872 int nbNodes = elem->NbNodes();
7873 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7874 aNds.reserve( nbNodes );
7875 mediumNodes.reserve( nbNodes );
7877 for(int i = 0; i < nbNodes; i++)
7879 const SMDS_MeshNode* n = elem->GetNode(i);
7881 if( elem->IsMediumNode( n ) )
7882 mediumNodes.push_back( n );
7884 aNds.push_back( n );
7886 if( aNds.empty() ) continue;
7887 SMDSAbs_ElementType aType = elem->GetType();
7889 //remove old quadratic element
7890 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7892 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7893 ReplaceElemInGroups(elem, NewElem, meshDS);
7894 if( theSm && NewElem )
7895 theSm->AddElement( NewElem );
7897 // remove medium nodes
7898 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7899 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7900 const SMDS_MeshNode* n = *nIt;
7901 if ( n->NbInverseElements() == 0 ) {
7902 if ( n->GetPosition()->GetShapeId() != theShapeID )
7903 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7904 ( n->GetPosition()->GetShapeId() ));
7906 meshDS->RemoveFreeNode( n, theSm );
7914 //=======================================================================
7915 //function : ConvertFromQuadratic
7917 //=======================================================================
7918 bool SMESH_MeshEditor::ConvertFromQuadratic()
7920 int nbCheckedElems = 0;
7921 if ( myMesh->HasShapeToMesh() )
7923 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7925 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7926 while ( smIt->more() ) {
7927 SMESH_subMesh* sm = smIt->next();
7928 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7929 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7935 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7936 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7938 SMESHDS_SubMesh *aSM = 0;
7939 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7945 //=======================================================================
7946 //function : SewSideElements
7948 //=======================================================================
7950 SMESH_MeshEditor::Sew_Error
7951 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7952 TIDSortedElemSet& theSide2,
7953 const SMDS_MeshNode* theFirstNode1,
7954 const SMDS_MeshNode* theFirstNode2,
7955 const SMDS_MeshNode* theSecondNode1,
7956 const SMDS_MeshNode* theSecondNode2)
7958 myLastCreatedElems.Clear();
7959 myLastCreatedNodes.Clear();
7961 MESSAGE ("::::SewSideElements()");
7962 if ( theSide1.size() != theSide2.size() )
7963 return SEW_DIFF_NB_OF_ELEMENTS;
7965 Sew_Error aResult = SEW_OK;
7967 // 1. Build set of faces representing each side
7968 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7969 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7971 // =======================================================================
7972 // 1. Build set of faces representing each side:
7973 // =======================================================================
7974 // a. build set of nodes belonging to faces
7975 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7976 // c. create temporary faces representing side of volumes if correspondent
7977 // face does not exist
7979 SMESHDS_Mesh* aMesh = GetMeshDS();
7980 SMDS_Mesh aTmpFacesMesh;
7981 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7982 set<const SMDS_MeshElement*> volSet1, volSet2;
7983 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7984 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7985 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7986 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7987 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7988 int iSide, iFace, iNode;
7990 for ( iSide = 0; iSide < 2; iSide++ ) {
7991 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7992 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7993 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7994 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7995 set<const SMDS_MeshElement*>::iterator vIt;
7996 TIDSortedElemSet::iterator eIt;
7997 set<const SMDS_MeshNode*>::iterator nIt;
7999 // check that given nodes belong to given elements
8000 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8001 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8002 int firstIndex = -1, secondIndex = -1;
8003 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8004 const SMDS_MeshElement* elem = *eIt;
8005 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
8006 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8007 if ( firstIndex > -1 && secondIndex > -1 ) break;
8009 if ( firstIndex < 0 || secondIndex < 0 ) {
8010 // we can simply return until temporary faces created
8011 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8014 // -----------------------------------------------------------
8015 // 1a. Collect nodes of existing faces
8016 // and build set of face nodes in order to detect missing
8017 // faces corresponing to sides of volumes
8018 // -----------------------------------------------------------
8020 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8022 // loop on the given element of a side
8023 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8024 //const SMDS_MeshElement* elem = *eIt;
8025 const SMDS_MeshElement* elem = *eIt;
8026 if ( elem->GetType() == SMDSAbs_Face ) {
8027 faceSet->insert( elem );
8028 set <const SMDS_MeshNode*> faceNodeSet;
8029 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8030 while ( nodeIt->more() ) {
8031 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8032 nodeSet->insert( n );
8033 faceNodeSet.insert( n );
8035 setOfFaceNodeSet.insert( faceNodeSet );
8037 else if ( elem->GetType() == SMDSAbs_Volume )
8038 volSet->insert( elem );
8040 // ------------------------------------------------------------------------------
8041 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8042 // ------------------------------------------------------------------------------
8044 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8045 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8046 while ( fIt->more() ) { // loop on faces sharing a node
8047 const SMDS_MeshElement* f = fIt->next();
8048 if ( faceSet->find( f ) == faceSet->end() ) {
8049 // check if all nodes are in nodeSet and
8050 // complete setOfFaceNodeSet if they are
8051 set <const SMDS_MeshNode*> faceNodeSet;
8052 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8053 bool allInSet = true;
8054 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8055 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8056 if ( nodeSet->find( n ) == nodeSet->end() )
8059 faceNodeSet.insert( n );
8062 faceSet->insert( f );
8063 setOfFaceNodeSet.insert( faceNodeSet );
8069 // -------------------------------------------------------------------------
8070 // 1c. Create temporary faces representing sides of volumes if correspondent
8071 // face does not exist
8072 // -------------------------------------------------------------------------
8074 if ( !volSet->empty() ) {
8075 //int nodeSetSize = nodeSet->size();
8077 // loop on given volumes
8078 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8079 SMDS_VolumeTool vol (*vIt);
8080 // loop on volume faces: find free faces
8081 // --------------------------------------
8082 list<const SMDS_MeshElement* > freeFaceList;
8083 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8084 if ( !vol.IsFreeFace( iFace ))
8086 // check if there is already a face with same nodes in a face set
8087 const SMDS_MeshElement* aFreeFace = 0;
8088 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8089 int nbNodes = vol.NbFaceNodes( iFace );
8090 set <const SMDS_MeshNode*> faceNodeSet;
8091 vol.GetFaceNodes( iFace, faceNodeSet );
8092 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8094 // no such a face is given but it still can exist, check it
8095 if ( nbNodes == 3 ) {
8096 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8098 else if ( nbNodes == 4 ) {
8099 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8102 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8103 aFreeFace = aMesh->FindFace(poly_nodes);
8107 // create a temporary face
8108 if ( nbNodes == 3 ) {
8109 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8111 else if ( nbNodes == 4 ) {
8112 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8115 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8116 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8120 freeFaceList.push_back( aFreeFace );
8122 } // loop on faces of a volume
8124 // choose one of several free faces
8125 // --------------------------------------
8126 if ( freeFaceList.size() > 1 ) {
8127 // choose a face having max nb of nodes shared by other elems of a side
8128 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8129 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8130 while ( fIt != freeFaceList.end() ) { // loop on free faces
8131 int nbSharedNodes = 0;
8132 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8133 while ( nodeIt->more() ) { // loop on free face nodes
8134 const SMDS_MeshNode* n =
8135 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8136 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8137 while ( invElemIt->more() ) {
8138 const SMDS_MeshElement* e = invElemIt->next();
8139 if ( faceSet->find( e ) != faceSet->end() )
8141 if ( elemSet->find( e ) != elemSet->end() )
8145 if ( nbSharedNodes >= maxNbNodes ) {
8146 maxNbNodes = nbSharedNodes;
8150 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8152 if ( freeFaceList.size() > 1 )
8154 // could not choose one face, use another way
8155 // choose a face most close to the bary center of the opposite side
8156 gp_XYZ aBC( 0., 0., 0. );
8157 set <const SMDS_MeshNode*> addedNodes;
8158 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8159 eIt = elemSet2->begin();
8160 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8161 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8162 while ( nodeIt->more() ) { // loop on free face nodes
8163 const SMDS_MeshNode* n =
8164 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8165 if ( addedNodes.insert( n ).second )
8166 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8169 aBC /= addedNodes.size();
8170 double minDist = DBL_MAX;
8171 fIt = freeFaceList.begin();
8172 while ( fIt != freeFaceList.end() ) { // loop on free faces
8174 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8175 while ( nodeIt->more() ) { // loop on free face nodes
8176 const SMDS_MeshNode* n =
8177 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8178 gp_XYZ p( n->X(),n->Y(),n->Z() );
8179 dist += ( aBC - p ).SquareModulus();
8181 if ( dist < minDist ) {
8183 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8186 fIt = freeFaceList.erase( fIt++ );
8189 } // choose one of several free faces of a volume
8191 if ( freeFaceList.size() == 1 ) {
8192 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8193 faceSet->insert( aFreeFace );
8194 // complete a node set with nodes of a found free face
8195 // for ( iNode = 0; iNode < ; iNode++ )
8196 // nodeSet->insert( fNodes[ iNode ] );
8199 } // loop on volumes of a side
8201 // // complete a set of faces if new nodes in a nodeSet appeared
8202 // // ----------------------------------------------------------
8203 // if ( nodeSetSize != nodeSet->size() ) {
8204 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8205 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8206 // while ( fIt->more() ) { // loop on faces sharing a node
8207 // const SMDS_MeshElement* f = fIt->next();
8208 // if ( faceSet->find( f ) == faceSet->end() ) {
8209 // // check if all nodes are in nodeSet and
8210 // // complete setOfFaceNodeSet if they are
8211 // set <const SMDS_MeshNode*> faceNodeSet;
8212 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8213 // bool allInSet = true;
8214 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8215 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8216 // if ( nodeSet->find( n ) == nodeSet->end() )
8217 // allInSet = false;
8219 // faceNodeSet.insert( n );
8221 // if ( allInSet ) {
8222 // faceSet->insert( f );
8223 // setOfFaceNodeSet.insert( faceNodeSet );
8229 } // Create temporary faces, if there are volumes given
8232 if ( faceSet1.size() != faceSet2.size() ) {
8233 // delete temporary faces: they are in reverseElements of actual nodes
8234 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8235 while ( tmpFaceIt->more() )
8236 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8237 MESSAGE("Diff nb of faces");
8238 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8241 // ============================================================
8242 // 2. Find nodes to merge:
8243 // bind a node to remove to a node to put instead
8244 // ============================================================
8246 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
8247 if ( theFirstNode1 != theFirstNode2 )
8248 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
8249 if ( theSecondNode1 != theSecondNode2 )
8250 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
8252 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8253 set< long > linkIdSet; // links to process
8254 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
8256 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
8257 list< NLink > linkList[2];
8258 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8259 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8260 // loop on links in linkList; find faces by links and append links
8261 // of the found faces to linkList
8262 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8263 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8264 NLink link[] = { *linkIt[0], *linkIt[1] };
8265 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
8266 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
8269 // by links, find faces in the face sets,
8270 // and find indices of link nodes in the found faces;
8271 // in a face set, there is only one or no face sharing a link
8272 // ---------------------------------------------------------------
8274 const SMDS_MeshElement* face[] = { 0, 0 };
8275 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
8276 vector<const SMDS_MeshNode*> fnodes1(9);
8277 vector<const SMDS_MeshNode*> fnodes2(9);
8278 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
8279 vector<const SMDS_MeshNode*> notLinkNodes1(6);
8280 vector<const SMDS_MeshNode*> notLinkNodes2(6);
8281 int iLinkNode[2][2];
8282 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8283 const SMDS_MeshNode* n1 = link[iSide].first;
8284 const SMDS_MeshNode* n2 = link[iSide].second;
8285 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8286 set< const SMDS_MeshElement* > fMap;
8287 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
8288 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
8289 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8290 while ( fIt->more() ) { // loop on faces sharing a node
8291 const SMDS_MeshElement* f = fIt->next();
8292 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8293 ! fMap.insert( f ).second ) // f encounters twice
8295 if ( face[ iSide ] ) {
8296 MESSAGE( "2 faces per link " );
8297 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
8301 faceSet->erase( f );
8302 // get face nodes and find ones of a link
8307 fnodes1.resize(f->NbNodes()+1);
8308 notLinkNodes1.resize(f->NbNodes()-2);
8311 fnodes2.resize(f->NbNodes()+1);
8312 notLinkNodes2.resize(f->NbNodes()-2);
8315 if(!f->IsQuadratic()) {
8316 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
8317 while ( nIt->more() ) {
8318 const SMDS_MeshNode* n =
8319 static_cast<const SMDS_MeshNode*>( nIt->next() );
8321 iLinkNode[ iSide ][ 0 ] = iNode;
8323 else if ( n == n2 ) {
8324 iLinkNode[ iSide ][ 1 ] = iNode;
8326 //else if ( notLinkNodes[ iSide ][ 0 ] )
8327 // notLinkNodes[ iSide ][ 1 ] = n;
8329 // notLinkNodes[ iSide ][ 0 ] = n;
8333 notLinkNodes1[nbl] = n;
8334 //notLinkNodes1.push_back(n);
8336 notLinkNodes2[nbl] = n;
8337 //notLinkNodes2.push_back(n);
8339 //faceNodes[ iSide ][ iNode++ ] = n;
8341 fnodes1[iNode++] = n;
8344 fnodes2[iNode++] = n;
8348 else { // f->IsQuadratic()
8349 const SMDS_QuadraticFaceOfNodes* F =
8350 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
8351 // use special nodes iterator
8352 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8353 while ( anIter->more() ) {
8354 const SMDS_MeshNode* n =
8355 static_cast<const SMDS_MeshNode*>( anIter->next() );
8357 iLinkNode[ iSide ][ 0 ] = iNode;
8359 else if ( n == n2 ) {
8360 iLinkNode[ iSide ][ 1 ] = iNode;
8365 notLinkNodes1[nbl] = n;
8368 notLinkNodes2[nbl] = n;
8372 fnodes1[iNode++] = n;
8375 fnodes2[iNode++] = n;
8379 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
8381 fnodes1[iNode] = fnodes1[0];
8384 fnodes2[iNode] = fnodes1[0];
8391 // check similarity of elements of the sides
8392 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8393 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8394 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8395 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8398 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8400 break; // do not return because it s necessary to remove tmp faces
8403 // set nodes to merge
8404 // -------------------
8406 if ( face[0] && face[1] ) {
8407 int nbNodes = face[0]->NbNodes();
8408 if ( nbNodes != face[1]->NbNodes() ) {
8409 MESSAGE("Diff nb of face nodes");
8410 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8411 break; // do not return because it s necessary to remove tmp faces
8413 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
8414 if ( nbNodes == 3 ) {
8415 //nReplaceMap.insert( TNodeNodeMap::value_type
8416 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8417 nReplaceMap.insert( TNodeNodeMap::value_type
8418 ( notLinkNodes1[0], notLinkNodes2[0] ));
8421 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8422 // analyse link orientation in faces
8423 int i1 = iLinkNode[ iSide ][ 0 ];
8424 int i2 = iLinkNode[ iSide ][ 1 ];
8425 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
8426 // if notLinkNodes are the first and the last ones, then
8427 // their order does not correspond to the link orientation
8428 if (( i1 == 1 && i2 == 2 ) ||
8429 ( i1 == 2 && i2 == 1 ))
8430 reverse[ iSide ] = !reverse[ iSide ];
8432 if ( reverse[0] == reverse[1] ) {
8433 //nReplaceMap.insert( TNodeNodeMap::value_type
8434 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8435 //nReplaceMap.insert( TNodeNodeMap::value_type
8436 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
8437 for(int nn=0; nn<nbNodes-2; nn++) {
8438 nReplaceMap.insert( TNodeNodeMap::value_type
8439 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
8443 //nReplaceMap.insert( TNodeNodeMap::value_type
8444 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
8445 //nReplaceMap.insert( TNodeNodeMap::value_type
8446 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
8447 for(int nn=0; nn<nbNodes-2; nn++) {
8448 nReplaceMap.insert( TNodeNodeMap::value_type
8449 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
8454 // add other links of the faces to linkList
8455 // -----------------------------------------
8457 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
8458 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8459 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
8460 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
8461 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
8462 if ( !iter_isnew.second ) { // already in a set: no need to process
8463 linkIdSet.erase( iter_isnew.first );
8465 else // new in set == encountered for the first time: add
8467 //const SMDS_MeshNode* n1 = nodes[ iNode ];
8468 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
8469 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
8470 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
8471 linkList[0].push_back ( NLink( n1, n2 ));
8472 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8476 } // loop on link lists
8478 if ( aResult == SEW_OK &&
8479 ( linkIt[0] != linkList[0].end() ||
8480 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
8481 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
8482 " " << (faceSetPtr[1]->empty()));
8483 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8486 // ====================================================================
8487 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8488 // ====================================================================
8490 // delete temporary faces: they are in reverseElements of actual nodes
8491 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8492 while ( tmpFaceIt->more() )
8493 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8495 if ( aResult != SEW_OK)
8498 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
8499 // loop on nodes replacement map
8500 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
8501 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
8502 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
8503 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
8504 nodeIDsToRemove.push_back( nToRemove->GetID() );
8505 // loop on elements sharing nToRemove
8506 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
8507 while ( invElemIt->more() ) {
8508 const SMDS_MeshElement* e = invElemIt->next();
8509 // get a new suite of nodes: make replacement
8510 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
8511 vector< const SMDS_MeshNode*> nodes( nbNodes );
8512 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8513 while ( nIt->more() ) {
8514 const SMDS_MeshNode* n =
8515 static_cast<const SMDS_MeshNode*>( nIt->next() );
8516 nnIt = nReplaceMap.find( n );
8517 if ( nnIt != nReplaceMap.end() ) {
8523 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8524 // elemIDsToRemove.push_back( e->GetID() );
8527 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8531 Remove( nodeIDsToRemove, true );
8536 //================================================================================
8538 * \brief Find corresponding nodes in two sets of faces
8539 * \param theSide1 - first face set
8540 * \param theSide2 - second first face
8541 * \param theFirstNode1 - a boundary node of set 1
8542 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8543 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8544 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8545 * \param nReplaceMap - output map of corresponding nodes
8546 * \retval bool - is a success or not
8548 //================================================================================
8551 //#define DEBUG_MATCHING_NODES
8554 SMESH_MeshEditor::Sew_Error
8555 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8556 set<const SMDS_MeshElement*>& theSide2,
8557 const SMDS_MeshNode* theFirstNode1,
8558 const SMDS_MeshNode* theFirstNode2,
8559 const SMDS_MeshNode* theSecondNode1,
8560 const SMDS_MeshNode* theSecondNode2,
8561 TNodeNodeMap & nReplaceMap)
8563 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8565 nReplaceMap.clear();
8566 if ( theFirstNode1 != theFirstNode2 )
8567 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8568 if ( theSecondNode1 != theSecondNode2 )
8569 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8571 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8572 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8574 list< NLink > linkList[2];
8575 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8576 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8578 // loop on links in linkList; find faces by links and append links
8579 // of the found faces to linkList
8580 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8581 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8582 NLink link[] = { *linkIt[0], *linkIt[1] };
8583 if ( linkSet.find( link[0] ) == linkSet.end() )
8586 // by links, find faces in the face sets,
8587 // and find indices of link nodes in the found faces;
8588 // in a face set, there is only one or no face sharing a link
8589 // ---------------------------------------------------------------
8591 const SMDS_MeshElement* face[] = { 0, 0 };
8592 list<const SMDS_MeshNode*> notLinkNodes[2];
8593 //bool reverse[] = { false, false }; // order of notLinkNodes
8595 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8597 const SMDS_MeshNode* n1 = link[iSide].first;
8598 const SMDS_MeshNode* n2 = link[iSide].second;
8599 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8600 set< const SMDS_MeshElement* > facesOfNode1;
8601 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8603 // during a loop of the first node, we find all faces around n1,
8604 // during a loop of the second node, we find one face sharing both n1 and n2
8605 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8606 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8607 while ( fIt->more() ) { // loop on faces sharing a node
8608 const SMDS_MeshElement* f = fIt->next();
8609 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8610 ! facesOfNode1.insert( f ).second ) // f encounters twice
8612 if ( face[ iSide ] ) {
8613 MESSAGE( "2 faces per link " );
8614 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8617 faceSet->erase( f );
8619 // get not link nodes
8620 int nbN = f->NbNodes();
8621 if ( f->IsQuadratic() )
8623 nbNodes[ iSide ] = nbN;
8624 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8625 int i1 = f->GetNodeIndex( n1 );
8626 int i2 = f->GetNodeIndex( n2 );
8627 int iEnd = nbN, iBeg = -1, iDelta = 1;
8628 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8630 std::swap( iEnd, iBeg ); iDelta = -1;
8635 if ( i == iEnd ) i = iBeg + iDelta;
8636 if ( i == i1 ) break;
8637 nodes.push_back ( f->GetNode( i ) );
8643 // check similarity of elements of the sides
8644 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8645 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8646 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8647 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8650 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8654 // set nodes to merge
8655 // -------------------
8657 if ( face[0] && face[1] ) {
8658 if ( nbNodes[0] != nbNodes[1] ) {
8659 MESSAGE("Diff nb of face nodes");
8660 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8662 #ifdef DEBUG_MATCHING_NODES
8663 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8664 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8665 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8667 int nbN = nbNodes[0];
8669 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8670 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8671 for ( int i = 0 ; i < nbN - 2; ++i ) {
8672 #ifdef DEBUG_MATCHING_NODES
8673 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8675 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8679 // add other links of the face 1 to linkList
8680 // -----------------------------------------
8682 const SMDS_MeshElement* f0 = face[0];
8683 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8684 for ( int i = 0; i < nbN; i++ )
8686 const SMDS_MeshNode* n2 = f0->GetNode( i );
8687 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8688 linkSet.insert( SMESH_TLink( n1, n2 ));
8689 if ( !iter_isnew.second ) { // already in a set: no need to process
8690 linkSet.erase( iter_isnew.first );
8692 else // new in set == encountered for the first time: add
8694 #ifdef DEBUG_MATCHING_NODES
8695 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8696 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8698 linkList[0].push_back ( NLink( n1, n2 ));
8699 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8704 } // loop on link lists
8709 //================================================================================
8711 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8712 \param theElems - the list of elements (edges or faces) to be replicated
8713 The nodes for duplication could be found from these elements
8714 \param theNodesNot - list of nodes to NOT replicate
8715 \param theAffectedElems - the list of elements (cells and edges) to which the
8716 replicated nodes should be associated to.
8717 \return TRUE if operation has been completed successfully, FALSE otherwise
8719 //================================================================================
8721 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
8722 const TIDSortedElemSet& theNodesNot,
8723 const TIDSortedElemSet& theAffectedElems )
8725 myLastCreatedElems.Clear();
8726 myLastCreatedNodes.Clear();
8728 if ( theElems.size() == 0 )
8731 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8736 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8737 // duplicate elements and nodes
8738 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
8739 // replce nodes by duplications
8740 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
8744 //================================================================================
8746 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8747 \param theMeshDS - mesh instance
8748 \param theElems - the elements replicated or modified (nodes should be changed)
8749 \param theNodesNot - nodes to NOT replicate
8750 \param theNodeNodeMap - relation of old node to new created node
8751 \param theIsDoubleElem - flag os to replicate element or modify
8752 \return TRUE if operation has been completed successfully, FALSE otherwise
8754 //================================================================================
8756 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
8757 const TIDSortedElemSet& theElems,
8758 const TIDSortedElemSet& theNodesNot,
8759 std::map< const SMDS_MeshNode*,
8760 const SMDS_MeshNode* >& theNodeNodeMap,
8761 const bool theIsDoubleElem )
8763 // iterate on through element and duplicate them (by nodes duplication)
8765 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8766 for ( ; elemItr != theElems.end(); ++elemItr )
8768 const SMDS_MeshElement* anElem = *elemItr;
8772 bool isDuplicate = false;
8773 // duplicate nodes to duplicate element
8774 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
8775 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8777 while ( anIter->more() )
8780 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8781 SMDS_MeshNode* aNewNode = aCurrNode;
8782 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
8783 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
8784 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
8787 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
8788 theNodeNodeMap[ aCurrNode ] = aNewNode;
8789 myLastCreatedNodes.Append( aNewNode );
8791 isDuplicate |= (aCurrNode != aNewNode);
8792 newNodes[ ind++ ] = aNewNode;
8797 if ( theIsDoubleElem )
8798 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
8800 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
8807 //================================================================================
8809 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8810 \param theNodes - identifiers of nodes to be doubled
8811 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
8812 nodes. If list of element identifiers is empty then nodes are doubled but
8813 they not assigned to elements
8814 \return TRUE if operation has been completed successfully, FALSE otherwise
8816 //================================================================================
8818 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
8819 const std::list< int >& theListOfModifiedElems )
8821 myLastCreatedElems.Clear();
8822 myLastCreatedNodes.Clear();
8824 if ( theListOfNodes.size() == 0 )
8827 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8831 // iterate through nodes and duplicate them
8833 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8835 std::list< int >::const_iterator aNodeIter;
8836 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
8838 int aCurr = *aNodeIter;
8839 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
8845 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
8848 anOldNodeToNewNode[ aNode ] = aNewNode;
8849 myLastCreatedNodes.Append( aNewNode );
8853 // Create map of new nodes for modified elements
8855 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
8857 std::list< int >::const_iterator anElemIter;
8858 for ( anElemIter = theListOfModifiedElems.begin();
8859 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
8861 int aCurr = *anElemIter;
8862 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
8866 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
8868 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8870 while ( anIter->more() )
8872 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8873 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
8875 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
8876 aNodeArr[ ind++ ] = aNewNode;
8879 aNodeArr[ ind++ ] = aCurrNode;
8881 anElemToNodes[ anElem ] = aNodeArr;
8884 // Change nodes of elements
8886 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
8887 anElemToNodesIter = anElemToNodes.begin();
8888 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
8890 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
8891 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
8893 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
8901 //================================================================================
8903 \brief Check if element located inside shape
8904 \return TRUE if IN or ON shape, FALSE otherwise
8906 //================================================================================
8908 template<class Classifier>
8909 bool isInside(const SMDS_MeshElement* theElem,
8910 Classifier& theClassifier,
8911 const double theTol)
8913 gp_XYZ centerXYZ (0, 0, 0);
8914 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
8915 while (aNodeItr->more())
8916 centerXYZ += TNodeXYZ(cast2Node( aNodeItr->next()));
8918 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
8919 theClassifier.Perform(aPnt, theTol);
8920 TopAbs_State aState = theClassifier.State();
8921 return (aState == TopAbs_IN || aState == TopAbs_ON );
8924 //================================================================================
8926 * \brief Classifier of the 3D point on the TopoDS_Face
8927 * with interaface suitable for isInside()
8929 //================================================================================
8931 struct _FaceClassifier
8933 Extrema_ExtPS _extremum;
8934 BRepAdaptor_Surface _surface;
8935 TopAbs_State _state;
8937 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
8939 _extremum.Initialize( _surface,
8940 _surface.FirstUParameter(), _surface.LastUParameter(),
8941 _surface.FirstVParameter(), _surface.LastVParameter(),
8942 _surface.Tolerance(), _surface.Tolerance() );
8944 void Perform(const gp_Pnt& aPnt, double theTol)
8946 _state = TopAbs_OUT;
8947 _extremum.Perform(aPnt);
8948 if ( _extremum.IsDone() )
8949 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
8950 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
8952 TopAbs_State State() const
8959 //================================================================================
8961 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8962 \param theElems - group of of elements (edges or faces) to be replicated
8963 \param theNodesNot - group of nodes not to replicate
8964 \param theShape - shape to detect affected elements (element which geometric center
8965 located on or inside shape).
8966 The replicated nodes should be associated to affected elements.
8967 \return TRUE if operation has been completed successfully, FALSE otherwise
8969 //================================================================================
8971 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
8972 const TIDSortedElemSet& theNodesNot,
8973 const TopoDS_Shape& theShape )
8975 if ( theShape.IsNull() )
8978 const double aTol = Precision::Confusion();
8979 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
8980 auto_ptr<_FaceClassifier> aFaceClassifier;
8981 if ( theShape.ShapeType() == TopAbs_SOLID )
8983 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
8984 bsc3d->PerformInfinitePoint(aTol);
8986 else if (theShape.ShapeType() == TopAbs_FACE )
8988 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
8991 // iterates on indicated elements and get elements by back references from their nodes
8992 TIDSortedElemSet anAffected;
8993 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8994 for ( ; elemItr != theElems.end(); ++elemItr )
8996 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9000 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9001 while ( nodeItr->more() )
9003 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9004 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9006 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9007 while ( backElemItr->more() )
9009 const SMDS_MeshElement* curElem = backElemItr->next();
9010 if ( curElem && theElems.find(curElem) == theElems.end() &&
9012 isInside( curElem, *bsc3d, aTol ) :
9013 isInside( curElem, *aFaceClassifier, aTol )))
9014 anAffected.insert( curElem );
9018 return DoubleNodes( theElems, theNodesNot, anAffected );
9021 //================================================================================
9023 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
9024 * The created 2D mesh elements based on nodes of free faces of boundary volumes
9025 * \return TRUE if operation has been completed successfully, FALSE otherwise
9027 //================================================================================
9029 bool SMESH_MeshEditor::Make2DMeshFrom3D()
9031 // iterates on volume elements and detect all free faces on them
9032 SMESHDS_Mesh* aMesh = GetMeshDS();
9036 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9039 const SMDS_MeshVolume* volume = vIt->next();
9040 SMDS_VolumeTool vTool( volume );
9041 vTool.SetExternalNormal();
9042 const bool isPoly = volume->IsPoly();
9043 const bool isQuad = volume->IsQuadratic();
9044 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9046 if (!vTool.IsFreeFace(iface))
9048 vector<const SMDS_MeshNode *> nodes;
9049 int nbFaceNodes = vTool.NbFaceNodes(iface);
9050 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9052 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9053 nodes.push_back(faceNodes[inode]);
9055 for ( inode = 1; inode < nbFaceNodes; inode += 2)
9056 nodes.push_back(faceNodes[inode]);
9058 // add new face based on volume nodes
9059 if (aMesh->FindFace( nodes ) )
9060 continue; // face already exsist
9061 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );