1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File : SMESH_MeshEditor.cxx
24 // Created : Mon Apr 12 16:10:22 2004
25 // Author : Edward AGAPOV (eap)
27 #include "SMESH_MeshEditor.hxx"
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_QuadraticFaceOfNodes.hxx"
36 #include "SMDS_MeshGroup.hxx"
38 #include "SMESHDS_Group.hxx"
39 #include "SMESHDS_Mesh.hxx"
41 #include "SMESH_subMesh.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_MesherHelper.hxx"
44 #include "SMESH_OctreeNode.hxx"
45 #include "SMESH_Group.hxx"
47 #include "utilities.h"
49 #include <BRep_Tool.hxx>
50 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <Extrema_GenExtPS.hxx>
53 #include <Extrema_POnSurf.hxx>
54 #include <Geom2d_Curve.hxx>
55 #include <GeomAdaptor_Surface.hxx>
56 #include <Geom_Curve.hxx>
57 #include <Geom_Surface.hxx>
58 #include <Precision.hxx>
59 #include <TColStd_ListOfInteger.hxx>
60 #include <TopAbs_State.hxx>
62 #include <TopExp_Explorer.hxx>
63 #include <TopTools_ListIteratorOfListOfShape.hxx>
64 #include <TopTools_ListOfShape.hxx>
65 #include <TopTools_SequenceOfShape.hxx>
67 #include <TopoDS_Face.hxx>
73 #include <gp_Trsf.hxx>
83 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
86 using namespace SMESH::Controls;
88 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
89 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
90 //typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> > TNodeOfNodeVecMap;
91 //typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr;
92 //typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> > TElemOfVecOfMapNodesMap;
94 //=======================================================================
96 * \brief SMDS_MeshNode -> gp_XYZ convertor
98 //=======================================================================
100 struct TNodeXYZ : public gp_XYZ
102 TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {}
103 double Distance( const SMDS_MeshNode* n )
105 return gp_Vec( *this, TNodeXYZ( n )).Magnitude();
107 double SquareDistance( const SMDS_MeshNode* n )
109 return gp_Vec( *this, TNodeXYZ( n )).SquareMagnitude();
113 //=======================================================================
114 //function : SMESH_MeshEditor
116 //=======================================================================
118 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
119 :myMesh( theMesh ) // theMesh may be NULL
123 //=======================================================================
127 //=======================================================================
130 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
131 const SMDSAbs_ElementType type,
135 SMDS_MeshElement* e = 0;
136 int nbnode = node.size();
137 SMESHDS_Mesh* mesh = GetMeshDS();
141 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
142 else e = mesh->AddEdge (node[0], node[1] );
143 else if ( nbnode == 3 )
144 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
145 else e = mesh->AddEdge (node[0], node[1], node[2] );
150 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
151 else e = mesh->AddFace (node[0], node[1], node[2] );
152 else if (nbnode == 4)
153 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
154 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
155 else if (nbnode == 6)
156 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
157 node[4], node[5], ID);
158 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
160 else if (nbnode == 8)
161 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
162 node[4], node[5], node[6], node[7], ID);
163 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
164 node[4], node[5], node[6], node[7] );
166 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
167 else e = mesh->AddPolygonalFace (node );
173 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
174 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
175 else if (nbnode == 5)
176 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
178 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
180 else if (nbnode == 6)
181 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
182 node[4], node[5], ID);
183 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
185 else if (nbnode == 8)
186 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
187 node[4], node[5], node[6], node[7], ID);
188 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7] );
190 else if (nbnode == 10)
191 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192 node[4], node[5], node[6], node[7],
193 node[8], node[9], ID);
194 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
195 node[4], node[5], node[6], node[7],
197 else if (nbnode == 13)
198 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199 node[4], node[5], node[6], node[7],
200 node[8], node[9], node[10],node[11],
202 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
203 node[4], node[5], node[6], node[7],
204 node[8], node[9], node[10],node[11],
206 else if (nbnode == 15)
207 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
208 node[4], node[5], node[6], node[7],
209 node[8], node[9], node[10],node[11],
210 node[12],node[13],node[14],ID);
211 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
212 node[4], node[5], node[6], node[7],
213 node[8], node[9], node[10],node[11],
214 node[12],node[13],node[14] );
215 else if (nbnode == 20)
216 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
217 node[4], node[5], node[6], node[7],
218 node[8], node[9], node[10],node[11],
219 node[12],node[13],node[14],node[15],
220 node[16],node[17],node[18],node[19],ID);
221 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
222 node[4], node[5], node[6], node[7],
223 node[8], node[9], node[10],node[11],
224 node[12],node[13],node[14],node[15],
225 node[16],node[17],node[18],node[19] );
231 //=======================================================================
235 //=======================================================================
237 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
238 const SMDSAbs_ElementType type,
242 vector<const SMDS_MeshNode*> nodes;
243 nodes.reserve( nodeIDs.size() );
244 vector<int>::const_iterator id = nodeIDs.begin();
245 while ( id != nodeIDs.end() ) {
246 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
247 nodes.push_back( node );
251 return AddElement( nodes, type, isPoly, ID );
254 //=======================================================================
256 //purpose : Remove a node or an element.
257 // Modify a compute state of sub-meshes which become empty
258 //=======================================================================
260 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
263 myLastCreatedElems.Clear();
264 myLastCreatedNodes.Clear();
266 SMESHDS_Mesh* aMesh = GetMeshDS();
267 set< SMESH_subMesh *> smmap;
269 list<int>::const_iterator it = theIDs.begin();
270 for ( ; it != theIDs.end(); it++ ) {
271 const SMDS_MeshElement * elem;
273 elem = aMesh->FindNode( *it );
275 elem = aMesh->FindElement( *it );
279 // Notify VERTEX sub-meshes about modification
281 const SMDS_MeshNode* node = cast2Node( elem );
282 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
283 if ( int aShapeID = node->GetPosition()->GetShapeId() )
284 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
287 // Find sub-meshes to notify about modification
288 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
289 // while ( nodeIt->more() ) {
290 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
291 // const SMDS_PositionPtr& aPosition = node->GetPosition();
292 // if ( aPosition.get() ) {
293 // if ( int aShapeID = aPosition->GetShapeId() ) {
294 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
295 // smmap.insert( sm );
302 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
304 aMesh->RemoveElement( elem );
307 // Notify sub-meshes about modification
308 if ( !smmap.empty() ) {
309 set< SMESH_subMesh *>::iterator smIt;
310 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
311 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
314 // // Check if the whole mesh becomes empty
315 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
316 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
321 //=======================================================================
322 //function : FindShape
323 //purpose : Return an index of the shape theElem is on
324 // or zero if a shape not found
325 //=======================================================================
327 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
329 myLastCreatedElems.Clear();
330 myLastCreatedNodes.Clear();
332 SMESHDS_Mesh * aMesh = GetMeshDS();
333 if ( aMesh->ShapeToMesh().IsNull() )
336 if ( theElem->GetType() == SMDSAbs_Node ) {
337 const SMDS_PositionPtr& aPosition =
338 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
339 if ( aPosition.get() )
340 return aPosition->GetShapeId();
345 TopoDS_Shape aShape; // the shape a node is on
346 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
347 while ( nodeIt->more() ) {
348 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
349 const SMDS_PositionPtr& aPosition = node->GetPosition();
350 if ( aPosition.get() ) {
351 int aShapeID = aPosition->GetShapeId();
352 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
354 if ( sm->Contains( theElem ))
356 if ( aShape.IsNull() )
357 aShape = aMesh->IndexToShape( aShapeID );
360 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
365 // None of nodes is on a proper shape,
366 // find the shape among ancestors of aShape on which a node is
367 if ( aShape.IsNull() ) {
368 //MESSAGE ("::FindShape() - NONE node is on shape")
371 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
372 for ( ; ancIt.More(); ancIt.Next() ) {
373 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
374 if ( sm && sm->Contains( theElem ))
375 return aMesh->ShapeToIndex( ancIt.Value() );
378 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
382 //=======================================================================
383 //function : IsMedium
385 //=======================================================================
387 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
388 const SMDSAbs_ElementType typeToCheck)
390 bool isMedium = false;
391 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
392 while (it->more() && !isMedium ) {
393 const SMDS_MeshElement* elem = it->next();
394 isMedium = elem->IsMediumNode(node);
399 //=======================================================================
400 //function : ShiftNodesQuadTria
402 // Shift nodes in the array corresponded to quadratic triangle
403 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
404 //=======================================================================
405 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
407 const SMDS_MeshNode* nd1 = aNodes[0];
408 aNodes[0] = aNodes[1];
409 aNodes[1] = aNodes[2];
411 const SMDS_MeshNode* nd2 = aNodes[3];
412 aNodes[3] = aNodes[4];
413 aNodes[4] = aNodes[5];
417 //=======================================================================
418 //function : GetNodesFromTwoTria
420 // Shift nodes in the array corresponded to quadratic triangle
421 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
422 //=======================================================================
423 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
424 const SMDS_MeshElement * theTria2,
425 const SMDS_MeshNode* N1[],
426 const SMDS_MeshNode* N2[])
428 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
431 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
434 if(it->more()) return false;
435 it = theTria2->nodesIterator();
438 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
441 if(it->more()) return false;
443 int sames[3] = {-1,-1,-1};
455 if(nbsames!=2) return false;
457 ShiftNodesQuadTria(N1);
459 ShiftNodesQuadTria(N1);
462 i = sames[0] + sames[1] + sames[2];
464 ShiftNodesQuadTria(N2);
466 // now we receive following N1 and N2 (using numeration as above image)
467 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
468 // i.e. first nodes from both arrays determ new diagonal
472 //=======================================================================
473 //function : InverseDiag
474 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
475 // but having other common link.
476 // Return False if args are improper
477 //=======================================================================
479 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
480 const SMDS_MeshElement * theTria2 )
482 myLastCreatedElems.Clear();
483 myLastCreatedNodes.Clear();
485 if (!theTria1 || !theTria2)
488 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
489 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
492 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
493 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
497 // put nodes in array and find out indices of the same ones
498 const SMDS_MeshNode* aNodes [6];
499 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
501 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
502 while ( it->more() ) {
503 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
505 if ( i > 2 ) // theTria2
506 // find same node of theTria1
507 for ( int j = 0; j < 3; j++ )
508 if ( aNodes[ i ] == aNodes[ j ]) {
517 return false; // theTria1 is not a triangle
518 it = theTria2->nodesIterator();
520 if ( i == 6 && it->more() )
521 return false; // theTria2 is not a triangle
524 // find indices of 1,2 and of A,B in theTria1
525 int iA = 0, iB = 0, i1 = 0, i2 = 0;
526 for ( i = 0; i < 6; i++ ) {
527 if ( sameInd [ i ] == 0 )
534 // nodes 1 and 2 should not be the same
535 if ( aNodes[ i1 ] == aNodes[ i2 ] )
539 aNodes[ iA ] = aNodes[ i2 ];
541 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
543 //MESSAGE( theTria1 << theTria2 );
545 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
546 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
548 //MESSAGE( theTria1 << theTria2 );
552 } // end if(F1 && F2)
554 // check case of quadratic faces
555 const SMDS_QuadraticFaceOfNodes* QF1 =
556 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
557 if(!QF1) return false;
558 const SMDS_QuadraticFaceOfNodes* QF2 =
559 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
560 if(!QF2) return false;
563 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
564 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
572 const SMDS_MeshNode* N1 [6];
573 const SMDS_MeshNode* N2 [6];
574 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
576 // now we receive following N1 and N2 (using numeration as above image)
577 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
578 // i.e. first nodes from both arrays determ new diagonal
580 const SMDS_MeshNode* N1new [6];
581 const SMDS_MeshNode* N2new [6];
594 // replaces nodes in faces
595 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
596 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
601 //=======================================================================
602 //function : findTriangles
603 //purpose : find triangles sharing theNode1-theNode2 link
604 //=======================================================================
606 static bool findTriangles(const SMDS_MeshNode * theNode1,
607 const SMDS_MeshNode * theNode2,
608 const SMDS_MeshElement*& theTria1,
609 const SMDS_MeshElement*& theTria2)
611 if ( !theNode1 || !theNode2 ) return false;
613 theTria1 = theTria2 = 0;
615 set< const SMDS_MeshElement* > emap;
616 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
618 const SMDS_MeshElement* elem = it->next();
619 if ( elem->NbNodes() == 3 )
622 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
624 const SMDS_MeshElement* elem = it->next();
625 if ( emap.find( elem ) != emap.end() )
627 // theTria1 must be element with minimum ID
628 if( theTria1->GetID() < elem->GetID() ) {
641 return ( theTria1 && theTria2 );
644 //=======================================================================
645 //function : InverseDiag
646 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
647 // with ones built on the same 4 nodes but having other common link.
648 // Return false if proper faces not found
649 //=======================================================================
651 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
652 const SMDS_MeshNode * theNode2)
654 myLastCreatedElems.Clear();
655 myLastCreatedNodes.Clear();
657 MESSAGE( "::InverseDiag()" );
659 const SMDS_MeshElement *tr1, *tr2;
660 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
663 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
664 //if (!F1) return false;
665 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
666 //if (!F2) return false;
669 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
670 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
674 // put nodes in array
675 // and find indices of 1,2 and of A in tr1 and of B in tr2
676 int i, iA1 = 0, i1 = 0;
677 const SMDS_MeshNode* aNodes1 [3];
678 SMDS_ElemIteratorPtr it;
679 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
680 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
681 if ( aNodes1[ i ] == theNode1 )
682 iA1 = i; // node A in tr1
683 else if ( aNodes1[ i ] != theNode2 )
687 const SMDS_MeshNode* aNodes2 [3];
688 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
689 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
690 if ( aNodes2[ i ] == theNode2 )
691 iB2 = i; // node B in tr2
692 else if ( aNodes2[ i ] != theNode1 )
696 // nodes 1 and 2 should not be the same
697 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
701 aNodes1[ iA1 ] = aNodes2[ i2 ];
703 aNodes2[ iB2 ] = aNodes1[ i1 ];
705 //MESSAGE( tr1 << tr2 );
707 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
708 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
710 //MESSAGE( tr1 << tr2 );
715 // check case of quadratic faces
716 const SMDS_QuadraticFaceOfNodes* QF1 =
717 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
718 if(!QF1) return false;
719 const SMDS_QuadraticFaceOfNodes* QF2 =
720 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
721 if(!QF2) return false;
722 return InverseDiag(tr1,tr2);
725 //=======================================================================
726 //function : getQuadrangleNodes
727 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
728 // fusion of triangles tr1 and tr2 having shared link on
729 // theNode1 and theNode2
730 //=======================================================================
732 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
733 const SMDS_MeshNode * theNode1,
734 const SMDS_MeshNode * theNode2,
735 const SMDS_MeshElement * tr1,
736 const SMDS_MeshElement * tr2 )
738 if( tr1->NbNodes() != tr2->NbNodes() )
740 // find the 4-th node to insert into tr1
741 const SMDS_MeshNode* n4 = 0;
742 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
744 while ( !n4 && i<3 ) {
745 const SMDS_MeshNode * n = cast2Node( it->next() );
747 bool isDiag = ( n == theNode1 || n == theNode2 );
751 // Make an array of nodes to be in a quadrangle
752 int iNode = 0, iFirstDiag = -1;
753 it = tr1->nodesIterator();
756 const SMDS_MeshNode * n = cast2Node( it->next() );
758 bool isDiag = ( n == theNode1 || n == theNode2 );
760 if ( iFirstDiag < 0 )
762 else if ( iNode - iFirstDiag == 1 )
763 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
765 else if ( n == n4 ) {
766 return false; // tr1 and tr2 should not have all the same nodes
768 theQuadNodes[ iNode++ ] = n;
770 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
771 theQuadNodes[ iNode ] = n4;
776 //=======================================================================
777 //function : DeleteDiag
778 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
779 // with a quadrangle built on the same 4 nodes.
780 // Return false if proper faces not found
781 //=======================================================================
783 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
784 const SMDS_MeshNode * theNode2)
786 myLastCreatedElems.Clear();
787 myLastCreatedNodes.Clear();
789 MESSAGE( "::DeleteDiag()" );
791 const SMDS_MeshElement *tr1, *tr2;
792 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
795 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
796 //if (!F1) return false;
797 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
798 //if (!F2) return false;
801 const SMDS_MeshNode* aNodes [ 4 ];
802 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
805 //MESSAGE( endl << tr1 << tr2 );
807 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
808 myLastCreatedElems.Append(tr1);
809 GetMeshDS()->RemoveElement( tr2 );
811 //MESSAGE( endl << tr1 );
816 // check case of quadratic faces
817 const SMDS_QuadraticFaceOfNodes* QF1 =
818 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
819 if(!QF1) return false;
820 const SMDS_QuadraticFaceOfNodes* QF2 =
821 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
822 if(!QF2) return false;
825 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
826 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
834 const SMDS_MeshNode* N1 [6];
835 const SMDS_MeshNode* N2 [6];
836 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
838 // now we receive following N1 and N2 (using numeration as above image)
839 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
840 // i.e. first nodes from both arrays determ new diagonal
842 const SMDS_MeshNode* aNodes[8];
852 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
853 myLastCreatedElems.Append(tr1);
854 GetMeshDS()->RemoveElement( tr2 );
856 // remove middle node (9)
857 GetMeshDS()->RemoveNode( N1[4] );
862 //=======================================================================
863 //function : Reorient
864 //purpose : Reverse theElement orientation
865 //=======================================================================
867 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
869 myLastCreatedElems.Clear();
870 myLastCreatedNodes.Clear();
874 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
875 if ( !it || !it->more() )
878 switch ( theElem->GetType() ) {
882 if(!theElem->IsQuadratic()) {
883 int i = theElem->NbNodes();
884 vector<const SMDS_MeshNode*> aNodes( i );
886 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
887 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
890 // quadratic elements
891 if(theElem->GetType()==SMDSAbs_Edge) {
892 vector<const SMDS_MeshNode*> aNodes(3);
893 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
894 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
895 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
896 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
899 int nbn = theElem->NbNodes();
900 vector<const SMDS_MeshNode*> aNodes(nbn);
901 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
903 for(; i<nbn/2; i++) {
904 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
906 for(i=0; i<nbn/2; i++) {
907 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
909 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
913 case SMDSAbs_Volume: {
914 if (theElem->IsPoly()) {
915 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
916 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
918 MESSAGE("Warning: bad volumic element");
922 int nbFaces = aPolyedre->NbFaces();
923 vector<const SMDS_MeshNode *> poly_nodes;
924 vector<int> quantities (nbFaces);
926 // reverse each face of the polyedre
927 for (int iface = 1; iface <= nbFaces; iface++) {
928 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
929 quantities[iface - 1] = nbFaceNodes;
931 for (inode = nbFaceNodes; inode >= 1; inode--) {
932 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
933 poly_nodes.push_back(curNode);
937 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
941 SMDS_VolumeTool vTool;
942 if ( !vTool.Set( theElem ))
945 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
954 //=======================================================================
955 //function : getBadRate
957 //=======================================================================
959 static double getBadRate (const SMDS_MeshElement* theElem,
960 SMESH::Controls::NumericalFunctorPtr& theCrit)
962 SMESH::Controls::TSequenceOfXYZ P;
963 if ( !theElem || !theCrit->GetPoints( theElem, P ))
965 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
966 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
969 //=======================================================================
970 //function : QuadToTri
971 //purpose : Cut quadrangles into triangles.
972 // theCrit is used to select a diagonal to cut
973 //=======================================================================
975 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
976 SMESH::Controls::NumericalFunctorPtr theCrit)
978 myLastCreatedElems.Clear();
979 myLastCreatedNodes.Clear();
981 MESSAGE( "::QuadToTri()" );
983 if ( !theCrit.get() )
986 SMESHDS_Mesh * aMesh = GetMeshDS();
988 Handle(Geom_Surface) surface;
989 SMESH_MesherHelper helper( *GetMesh() );
991 TIDSortedElemSet::iterator itElem;
992 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
993 const SMDS_MeshElement* elem = *itElem;
994 if ( !elem || elem->GetType() != SMDSAbs_Face )
996 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
999 // retrieve element nodes
1000 const SMDS_MeshNode* aNodes [8];
1001 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1003 while ( itN->more() )
1004 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1006 // compare two sets of possible triangles
1007 double aBadRate1, aBadRate2; // to what extent a set is bad
1008 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1009 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1010 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1012 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1013 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1014 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1016 int aShapeId = FindShape( elem );
1017 const SMDS_MeshElement* newElem = 0;
1019 if( !elem->IsQuadratic() ) {
1021 // split liner quadrangle
1023 if ( aBadRate1 <= aBadRate2 ) {
1024 // tr1 + tr2 is better
1025 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1026 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1029 // tr3 + tr4 is better
1030 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1031 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1036 // split quadratic quadrangle
1038 // get surface elem is on
1039 if ( aShapeId != helper.GetSubShapeID() ) {
1043 shape = aMesh->IndexToShape( aShapeId );
1044 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1045 TopoDS_Face face = TopoDS::Face( shape );
1046 surface = BRep_Tool::Surface( face );
1047 if ( !surface.IsNull() )
1048 helper.SetSubShape( shape );
1052 const SMDS_MeshNode* aNodes [8];
1053 const SMDS_MeshNode* inFaceNode = 0;
1054 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1056 while ( itN->more() ) {
1057 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1058 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1059 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1061 inFaceNode = aNodes[ i-1 ];
1064 // find middle point for (0,1,2,3)
1065 // and create a node in this point;
1067 if ( surface.IsNull() ) {
1069 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1073 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1076 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1078 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1080 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1081 myLastCreatedNodes.Append(newN);
1083 // create a new element
1084 const SMDS_MeshNode* N[6];
1085 if ( aBadRate1 <= aBadRate2 ) {
1092 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1093 aNodes[6], aNodes[7], newN );
1102 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1103 aNodes[7], aNodes[4], newN );
1105 aMesh->ChangeElementNodes( elem, N, 6 );
1109 // care of a new element
1111 myLastCreatedElems.Append(newElem);
1112 AddToSameGroups( newElem, elem, aMesh );
1114 // put a new triangle on the same shape
1116 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1121 //=======================================================================
1122 //function : BestSplit
1123 //purpose : Find better diagonal for cutting.
1124 //=======================================================================
1125 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1126 SMESH::Controls::NumericalFunctorPtr theCrit)
1128 myLastCreatedElems.Clear();
1129 myLastCreatedNodes.Clear();
1134 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1137 if( theQuad->NbNodes()==4 ||
1138 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1140 // retrieve element nodes
1141 const SMDS_MeshNode* aNodes [4];
1142 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1144 //while (itN->more())
1146 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1148 // compare two sets of possible triangles
1149 double aBadRate1, aBadRate2; // to what extent a set is bad
1150 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1151 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1152 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1154 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1155 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1156 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1158 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1159 return 1; // diagonal 1-3
1161 return 2; // diagonal 2-4
1166 //=======================================================================
1167 //function : AddToSameGroups
1168 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1169 //=======================================================================
1171 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1172 const SMDS_MeshElement* elemInGroups,
1173 SMESHDS_Mesh * aMesh)
1175 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1176 if (!groups.empty()) {
1177 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1178 for ( ; grIt != groups.end(); grIt++ ) {
1179 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1180 if ( group && group->Contains( elemInGroups ))
1181 group->SMDSGroup().Add( elemToAdd );
1187 //=======================================================================
1188 //function : RemoveElemFromGroups
1189 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1190 //=======================================================================
1191 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1192 SMESHDS_Mesh * aMesh)
1194 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1195 if (!groups.empty())
1197 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1198 for (; GrIt != groups.end(); GrIt++)
1200 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1201 if (!grp || grp->IsEmpty()) continue;
1202 grp->SMDSGroup().Remove(removeelem);
1207 //=======================================================================
1208 //function : ReplaceElemInGroups
1209 //purpose : replace elemToRm by elemToAdd in the all groups
1210 //=======================================================================
1212 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1213 const SMDS_MeshElement* elemToAdd,
1214 SMESHDS_Mesh * aMesh)
1216 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1217 if (!groups.empty()) {
1218 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1219 for ( ; grIt != groups.end(); grIt++ ) {
1220 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1221 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1222 group->SMDSGroup().Add( elemToAdd );
1227 //=======================================================================
1228 //function : QuadToTri
1229 //purpose : Cut quadrangles into triangles.
1230 // theCrit is used to select a diagonal to cut
1231 //=======================================================================
1233 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1234 const bool the13Diag)
1236 myLastCreatedElems.Clear();
1237 myLastCreatedNodes.Clear();
1239 MESSAGE( "::QuadToTri()" );
1241 SMESHDS_Mesh * aMesh = GetMeshDS();
1243 Handle(Geom_Surface) surface;
1244 SMESH_MesherHelper helper( *GetMesh() );
1246 TIDSortedElemSet::iterator itElem;
1247 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1248 const SMDS_MeshElement* elem = *itElem;
1249 if ( !elem || elem->GetType() != SMDSAbs_Face )
1251 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1252 if(!isquad) continue;
1254 if(elem->NbNodes()==4) {
1255 // retrieve element nodes
1256 const SMDS_MeshNode* aNodes [4];
1257 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1259 while ( itN->more() )
1260 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1262 int aShapeId = FindShape( elem );
1263 const SMDS_MeshElement* newElem = 0;
1265 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1266 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1269 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1270 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1272 myLastCreatedElems.Append(newElem);
1273 // put a new triangle on the same shape and add to the same groups
1275 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1276 AddToSameGroups( newElem, elem, aMesh );
1279 // Quadratic quadrangle
1281 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1283 // get surface elem is on
1284 int aShapeId = FindShape( elem );
1285 if ( aShapeId != helper.GetSubShapeID() ) {
1289 shape = aMesh->IndexToShape( aShapeId );
1290 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1291 TopoDS_Face face = TopoDS::Face( shape );
1292 surface = BRep_Tool::Surface( face );
1293 if ( !surface.IsNull() )
1294 helper.SetSubShape( shape );
1298 const SMDS_MeshNode* aNodes [8];
1299 const SMDS_MeshNode* inFaceNode = 0;
1300 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1302 while ( itN->more() ) {
1303 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1304 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1305 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1307 inFaceNode = aNodes[ i-1 ];
1311 // find middle point for (0,1,2,3)
1312 // and create a node in this point;
1314 if ( surface.IsNull() ) {
1316 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1320 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1323 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1325 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1327 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1328 myLastCreatedNodes.Append(newN);
1330 // create a new element
1331 const SMDS_MeshElement* newElem = 0;
1332 const SMDS_MeshNode* N[6];
1340 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1341 aNodes[6], aNodes[7], newN );
1350 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1351 aNodes[7], aNodes[4], newN );
1353 myLastCreatedElems.Append(newElem);
1354 aMesh->ChangeElementNodes( elem, N, 6 );
1355 // put a new triangle on the same shape and add to the same groups
1357 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1358 AddToSameGroups( newElem, elem, aMesh );
1365 //=======================================================================
1366 //function : getAngle
1368 //=======================================================================
1370 double getAngle(const SMDS_MeshElement * tr1,
1371 const SMDS_MeshElement * tr2,
1372 const SMDS_MeshNode * n1,
1373 const SMDS_MeshNode * n2)
1375 double angle = 2*PI; // bad angle
1378 SMESH::Controls::TSequenceOfXYZ P1, P2;
1379 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1380 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1383 if(!tr1->IsQuadratic())
1384 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1386 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1387 if ( N1.SquareMagnitude() <= gp::Resolution() )
1389 if(!tr2->IsQuadratic())
1390 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1392 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1393 if ( N2.SquareMagnitude() <= gp::Resolution() )
1396 // find the first diagonal node n1 in the triangles:
1397 // take in account a diagonal link orientation
1398 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1399 for ( int t = 0; t < 2; t++ ) {
1400 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1401 int i = 0, iDiag = -1;
1402 while ( it->more()) {
1403 const SMDS_MeshElement *n = it->next();
1404 if ( n == n1 || n == n2 )
1408 if ( i - iDiag == 1 )
1409 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1417 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1420 angle = N1.Angle( N2 );
1425 // =================================================
1426 // class generating a unique ID for a pair of nodes
1427 // and able to return nodes by that ID
1428 // =================================================
1432 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1433 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1436 long GetLinkID (const SMDS_MeshNode * n1,
1437 const SMDS_MeshNode * n2) const
1439 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1442 bool GetNodes (const long theLinkID,
1443 const SMDS_MeshNode* & theNode1,
1444 const SMDS_MeshNode* & theNode2) const
1446 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1447 if ( !theNode1 ) return false;
1448 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1449 if ( !theNode2 ) return false;
1455 const SMESHDS_Mesh* myMesh;
1460 //=======================================================================
1461 //function : TriToQuad
1462 //purpose : Fuse neighbour triangles into quadrangles.
1463 // theCrit is used to select a neighbour to fuse with.
1464 // theMaxAngle is a max angle between element normals at which
1465 // fusion is still performed.
1466 //=======================================================================
1468 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1469 SMESH::Controls::NumericalFunctorPtr theCrit,
1470 const double theMaxAngle)
1472 myLastCreatedElems.Clear();
1473 myLastCreatedNodes.Clear();
1475 MESSAGE( "::TriToQuad()" );
1477 if ( !theCrit.get() )
1480 SMESHDS_Mesh * aMesh = GetMeshDS();
1482 // Prepare data for algo: build
1483 // 1. map of elements with their linkIDs
1484 // 2. map of linkIDs with their elements
1486 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1487 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1488 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1489 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1491 TIDSortedElemSet::iterator itElem;
1492 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1493 const SMDS_MeshElement* elem = *itElem;
1494 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1495 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1496 if(!IsTria) continue;
1498 // retrieve element nodes
1499 const SMDS_MeshNode* aNodes [4];
1500 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1503 aNodes[ i++ ] = cast2Node( itN->next() );
1504 aNodes[ 3 ] = aNodes[ 0 ];
1507 for ( i = 0; i < 3; i++ ) {
1508 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1509 // check if elements sharing a link can be fused
1510 itLE = mapLi_listEl.find( link );
1511 if ( itLE != mapLi_listEl.end() ) {
1512 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1514 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1515 //if ( FindShape( elem ) != FindShape( elem2 ))
1516 // continue; // do not fuse triangles laying on different shapes
1517 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1518 continue; // avoid making badly shaped quads
1519 (*itLE).second.push_back( elem );
1522 mapLi_listEl[ link ].push_back( elem );
1524 mapEl_setLi [ elem ].insert( link );
1527 // Clean the maps from the links shared by a sole element, ie
1528 // links to which only one element is bound in mapLi_listEl
1530 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1531 int nbElems = (*itLE).second.size();
1532 if ( nbElems < 2 ) {
1533 const SMDS_MeshElement* elem = (*itLE).second.front();
1534 SMESH_TLink link = (*itLE).first;
1535 mapEl_setLi[ elem ].erase( link );
1536 if ( mapEl_setLi[ elem ].empty() )
1537 mapEl_setLi.erase( elem );
1541 // Algo: fuse triangles into quadrangles
1543 while ( ! mapEl_setLi.empty() ) {
1544 // Look for the start element:
1545 // the element having the least nb of shared links
1546 const SMDS_MeshElement* startElem = 0;
1548 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1549 int nbLinks = (*itEL).second.size();
1550 if ( nbLinks < minNbLinks ) {
1551 startElem = (*itEL).first;
1552 minNbLinks = nbLinks;
1553 if ( minNbLinks == 1 )
1558 // search elements to fuse starting from startElem or links of elements
1559 // fused earlyer - startLinks
1560 list< SMESH_TLink > startLinks;
1561 while ( startElem || !startLinks.empty() ) {
1562 while ( !startElem && !startLinks.empty() ) {
1563 // Get an element to start, by a link
1564 SMESH_TLink linkId = startLinks.front();
1565 startLinks.pop_front();
1566 itLE = mapLi_listEl.find( linkId );
1567 if ( itLE != mapLi_listEl.end() ) {
1568 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1569 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1570 for ( ; itE != listElem.end() ; itE++ )
1571 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1573 mapLi_listEl.erase( itLE );
1578 // Get candidates to be fused
1579 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1580 const SMESH_TLink *link12, *link13;
1582 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1583 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1584 ASSERT( !setLi.empty() );
1585 set< SMESH_TLink >::iterator itLi;
1586 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1588 const SMESH_TLink & link = (*itLi);
1589 itLE = mapLi_listEl.find( link );
1590 if ( itLE == mapLi_listEl.end() )
1593 const SMDS_MeshElement* elem = (*itLE).second.front();
1595 elem = (*itLE).second.back();
1596 mapLi_listEl.erase( itLE );
1597 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1608 // add other links of elem to list of links to re-start from
1609 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1610 set< SMESH_TLink >::iterator it;
1611 for ( it = links.begin(); it != links.end(); it++ ) {
1612 const SMESH_TLink& link2 = (*it);
1613 if ( link2 != link )
1614 startLinks.push_back( link2 );
1618 // Get nodes of possible quadrangles
1619 const SMDS_MeshNode *n12 [4], *n13 [4];
1620 bool Ok12 = false, Ok13 = false;
1621 const SMDS_MeshNode *linkNode1, *linkNode2;
1623 linkNode1 = link12->first;
1624 linkNode2 = link12->second;
1625 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1629 linkNode1 = link13->first;
1630 linkNode2 = link13->second;
1631 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1635 // Choose a pair to fuse
1636 if ( Ok12 && Ok13 ) {
1637 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1638 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1639 double aBadRate12 = getBadRate( &quad12, theCrit );
1640 double aBadRate13 = getBadRate( &quad13, theCrit );
1641 if ( aBadRate13 < aBadRate12 )
1648 // and remove fused elems and removed links from the maps
1649 mapEl_setLi.erase( tr1 );
1651 mapEl_setLi.erase( tr2 );
1652 mapLi_listEl.erase( *link12 );
1653 if(tr1->NbNodes()==3) {
1654 if( tr1->GetID() < tr2->GetID() ) {
1655 aMesh->ChangeElementNodes( tr1, n12, 4 );
1656 myLastCreatedElems.Append(tr1);
1657 aMesh->RemoveElement( tr2 );
1660 aMesh->ChangeElementNodes( tr2, n12, 4 );
1661 myLastCreatedElems.Append(tr2);
1662 aMesh->RemoveElement( tr1);
1666 const SMDS_MeshNode* N1 [6];
1667 const SMDS_MeshNode* N2 [6];
1668 GetNodesFromTwoTria(tr1,tr2,N1,N2);
1669 // now we receive following N1 and N2 (using numeration as above image)
1670 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1671 // i.e. first nodes from both arrays determ new diagonal
1672 const SMDS_MeshNode* aNodes[8];
1681 if( tr1->GetID() < tr2->GetID() ) {
1682 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1683 myLastCreatedElems.Append(tr1);
1684 GetMeshDS()->RemoveElement( tr2 );
1687 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1688 myLastCreatedElems.Append(tr2);
1689 GetMeshDS()->RemoveElement( tr1 );
1691 // remove middle node (9)
1692 GetMeshDS()->RemoveNode( N1[4] );
1696 mapEl_setLi.erase( tr3 );
1697 mapLi_listEl.erase( *link13 );
1698 if(tr1->NbNodes()==3) {
1699 if( tr1->GetID() < tr2->GetID() ) {
1700 aMesh->ChangeElementNodes( tr1, n13, 4 );
1701 myLastCreatedElems.Append(tr1);
1702 aMesh->RemoveElement( tr3 );
1705 aMesh->ChangeElementNodes( tr3, n13, 4 );
1706 myLastCreatedElems.Append(tr3);
1707 aMesh->RemoveElement( tr1 );
1711 const SMDS_MeshNode* N1 [6];
1712 const SMDS_MeshNode* N2 [6];
1713 GetNodesFromTwoTria(tr1,tr3,N1,N2);
1714 // now we receive following N1 and N2 (using numeration as above image)
1715 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1716 // i.e. first nodes from both arrays determ new diagonal
1717 const SMDS_MeshNode* aNodes[8];
1726 if( tr1->GetID() < tr2->GetID() ) {
1727 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1728 myLastCreatedElems.Append(tr1);
1729 GetMeshDS()->RemoveElement( tr3 );
1732 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1733 myLastCreatedElems.Append(tr3);
1734 GetMeshDS()->RemoveElement( tr1 );
1736 // remove middle node (9)
1737 GetMeshDS()->RemoveNode( N1[4] );
1741 // Next element to fuse: the rejected one
1743 startElem = Ok12 ? tr3 : tr2;
1745 } // if ( startElem )
1746 } // while ( startElem || !startLinks.empty() )
1747 } // while ( ! mapEl_setLi.empty() )
1753 /*#define DUMPSO(txt) \
1754 // cout << txt << endl;
1755 //=============================================================================
1759 //=============================================================================
1760 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1764 int tmp = idNodes[ i1 ];
1765 idNodes[ i1 ] = idNodes[ i2 ];
1766 idNodes[ i2 ] = tmp;
1767 gp_Pnt Ptmp = P[ i1 ];
1770 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1773 //=======================================================================
1774 //function : SortQuadNodes
1775 //purpose : Set 4 nodes of a quadrangle face in a good order.
1776 // Swap 1<->2 or 2<->3 nodes and correspondingly return
1778 //=======================================================================
1780 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1785 for ( i = 0; i < 4; i++ ) {
1786 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1788 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1791 gp_Vec V1(P[0], P[1]);
1792 gp_Vec V2(P[0], P[2]);
1793 gp_Vec V3(P[0], P[3]);
1795 gp_Vec Cross1 = V1 ^ V2;
1796 gp_Vec Cross2 = V2 ^ V3;
1799 if (Cross1.Dot(Cross2) < 0)
1804 if (Cross1.Dot(Cross2) < 0)
1808 swap ( i, i + 1, idNodes, P );
1810 // for ( int ii = 0; ii < 4; ii++ ) {
1811 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1812 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1818 //=======================================================================
1819 //function : SortHexaNodes
1820 //purpose : Set 8 nodes of a hexahedron in a good order.
1821 // Return success status
1822 //=======================================================================
1824 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1829 DUMPSO( "INPUT: ========================================");
1830 for ( i = 0; i < 8; i++ ) {
1831 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1832 if ( !n ) return false;
1833 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1834 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1836 DUMPSO( "========================================");
1839 set<int> faceNodes; // ids of bottom face nodes, to be found
1840 set<int> checkedId1; // ids of tried 2-nd nodes
1841 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1842 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
1843 int iMin, iLoop1 = 0;
1845 // Loop to try the 2-nd nodes
1847 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1849 // Find not checked 2-nd node
1850 for ( i = 1; i < 8; i++ )
1851 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1852 int id1 = idNodes[i];
1853 swap ( 1, i, idNodes, P );
1854 checkedId1.insert ( id1 );
1858 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1859 // ie that all but meybe one (id3 which is on the same face) nodes
1860 // lay on the same side from the triangle plane.
1862 bool manyInPlane = false; // more than 4 nodes lay in plane
1864 while ( ++iLoop2 < 6 ) {
1866 // get 1-2-3 plane coeffs
1867 Standard_Real A, B, C, D;
1868 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1869 if ( N.SquareMagnitude() > gp::Resolution() )
1871 gp_Pln pln ( P[0], N );
1872 pln.Coefficients( A, B, C, D );
1874 // find the node (iMin) closest to pln
1875 Standard_Real dist[ 8 ], minDist = DBL_MAX;
1877 for ( i = 3; i < 8; i++ ) {
1878 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1879 if ( fabs( dist[i] ) < minDist ) {
1880 minDist = fabs( dist[i] );
1883 if ( fabs( dist[i] ) <= tol )
1884 idInPln.insert( idNodes[i] );
1887 // there should not be more than 4 nodes in bottom plane
1888 if ( idInPln.size() > 1 )
1890 DUMPSO( "### idInPln.size() = " << idInPln.size());
1891 // idInPlane does not contain the first 3 nodes
1892 if ( manyInPlane || idInPln.size() == 5)
1893 return false; // all nodes in one plane
1896 // set the 1-st node to be not in plane
1897 for ( i = 3; i < 8; i++ ) {
1898 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1899 DUMPSO( "### Reset 0-th node");
1900 swap( 0, i, idNodes, P );
1905 // reset to re-check second nodes
1906 leastDist = DBL_MAX;
1910 break; // from iLoop2;
1913 // check that the other 4 nodes are on the same side
1914 bool sameSide = true;
1915 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1916 for ( i = 3; sameSide && i < 8; i++ ) {
1918 sameSide = ( isNeg == dist[i] <= 0.);
1921 // keep best solution
1922 if ( sameSide && minDist < leastDist ) {
1923 leastDist = minDist;
1925 faceNodes.insert( idNodes[ 1 ] );
1926 faceNodes.insert( idNodes[ 2 ] );
1927 faceNodes.insert( idNodes[ iMin ] );
1928 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1929 << " leastDist = " << leastDist);
1930 if ( leastDist <= DBL_MIN )
1935 // set next 3-d node to check
1936 int iNext = 2 + iLoop2;
1938 DUMPSO( "Try 2-nd");
1939 swap ( 2, iNext, idNodes, P );
1941 } // while ( iLoop2 < 6 )
1944 if ( faceNodes.empty() ) return false;
1946 // Put the faceNodes in proper places
1947 for ( i = 4; i < 8; i++ ) {
1948 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1949 // find a place to put
1951 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1953 DUMPSO( "Set faceNodes");
1954 swap ( iTo, i, idNodes, P );
1959 // Set nodes of the found bottom face in good order
1960 DUMPSO( " Found bottom face: ");
1961 i = SortQuadNodes( theMesh, idNodes );
1963 gp_Pnt Ptmp = P[ i ];
1968 // for ( int ii = 0; ii < 4; ii++ ) {
1969 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1970 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1973 // Gravity center of the top and bottom faces
1974 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1975 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1977 // Get direction from the bottom to the top face
1978 gp_Vec upDir ( aGCb, aGCt );
1979 Standard_Real upDirSize = upDir.Magnitude();
1980 if ( upDirSize <= gp::Resolution() ) return false;
1983 // Assure that the bottom face normal points up
1984 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1985 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1986 if ( Nb.Dot( upDir ) < 0 ) {
1987 DUMPSO( "Reverse bottom face");
1988 swap( 1, 3, idNodes, P );
1991 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1992 Standard_Real minDist = DBL_MAX;
1993 for ( i = 4; i < 8; i++ ) {
1994 // projection of P[i] to the plane defined by P[0] and upDir
1995 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1996 Standard_Real sqDist = P[0].SquareDistance( Pp );
1997 if ( sqDist < minDist ) {
2002 DUMPSO( "Set 4-th");
2003 swap ( 4, iMin, idNodes, P );
2005 // Set nodes of the top face in good order
2006 DUMPSO( "Sort top face");
2007 i = SortQuadNodes( theMesh, &idNodes[4] );
2010 gp_Pnt Ptmp = P[ i ];
2015 // Assure that direction of the top face normal is from the bottom face
2016 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2017 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2018 if ( Nt.Dot( upDir ) < 0 ) {
2019 DUMPSO( "Reverse top face");
2020 swap( 5, 7, idNodes, P );
2023 // DUMPSO( "OUTPUT: ========================================");
2024 // for ( i = 0; i < 8; i++ ) {
2025 // float *p = ugrid->GetPoint(idNodes[i]);
2026 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2032 //================================================================================
2034 * \brief Return nodes linked to the given one
2035 * \param theNode - the node
2036 * \param linkedNodes - the found nodes
2037 * \param type - the type of elements to check
2039 * Medium nodes are ignored
2041 //================================================================================
2043 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2044 TIDSortedElemSet & linkedNodes,
2045 SMDSAbs_ElementType type )
2047 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2048 while ( elemIt->more() )
2050 const SMDS_MeshElement* elem = elemIt->next();
2051 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2052 if ( elem->GetType() == SMDSAbs_Volume )
2054 SMDS_VolumeTool vol( elem );
2055 while ( nodeIt->more() ) {
2056 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2057 if ( theNode != n && vol.IsLinked( theNode, n ))
2058 linkedNodes.insert( n );
2063 for ( int i = 0; nodeIt->more(); ++i ) {
2064 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2065 if ( n == theNode ) {
2066 int iBefore = i - 1;
2068 if ( elem->IsQuadratic() ) {
2069 int nb = elem->NbNodes() / 2;
2070 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2071 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2073 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2074 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2081 //=======================================================================
2082 //function : laplacianSmooth
2083 //purpose : pulls theNode toward the center of surrounding nodes directly
2084 // connected to that node along an element edge
2085 //=======================================================================
2087 void laplacianSmooth(const SMDS_MeshNode* theNode,
2088 const Handle(Geom_Surface)& theSurface,
2089 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2091 // find surrounding nodes
2093 TIDSortedElemSet nodeSet;
2094 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2096 // compute new coodrs
2098 double coord[] = { 0., 0., 0. };
2099 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2100 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2101 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2102 if ( theSurface.IsNull() ) { // smooth in 3D
2103 coord[0] += node->X();
2104 coord[1] += node->Y();
2105 coord[2] += node->Z();
2107 else { // smooth in 2D
2108 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2109 gp_XY* uv = theUVMap[ node ];
2110 coord[0] += uv->X();
2111 coord[1] += uv->Y();
2114 int nbNodes = nodeSet.size();
2117 coord[0] /= nbNodes;
2118 coord[1] /= nbNodes;
2120 if ( !theSurface.IsNull() ) {
2121 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2122 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2123 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2129 coord[2] /= nbNodes;
2133 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2136 //=======================================================================
2137 //function : centroidalSmooth
2138 //purpose : pulls theNode toward the element-area-weighted centroid of the
2139 // surrounding elements
2140 //=======================================================================
2142 void centroidalSmooth(const SMDS_MeshNode* theNode,
2143 const Handle(Geom_Surface)& theSurface,
2144 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2146 gp_XYZ aNewXYZ(0.,0.,0.);
2147 SMESH::Controls::Area anAreaFunc;
2148 double totalArea = 0.;
2153 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2154 while ( elemIt->more() )
2156 const SMDS_MeshElement* elem = elemIt->next();
2159 gp_XYZ elemCenter(0.,0.,0.);
2160 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2161 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2162 int nn = elem->NbNodes();
2163 if(elem->IsQuadratic()) nn = nn/2;
2165 //while ( itN->more() ) {
2167 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2169 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2170 aNodePoints.push_back( aP );
2171 if ( !theSurface.IsNull() ) { // smooth in 2D
2172 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2173 gp_XY* uv = theUVMap[ aNode ];
2174 aP.SetCoord( uv->X(), uv->Y(), 0. );
2178 double elemArea = anAreaFunc.GetValue( aNodePoints );
2179 totalArea += elemArea;
2181 aNewXYZ += elemCenter * elemArea;
2183 aNewXYZ /= totalArea;
2184 if ( !theSurface.IsNull() ) {
2185 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2186 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2191 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2194 //=======================================================================
2195 //function : getClosestUV
2196 //purpose : return UV of closest projection
2197 //=======================================================================
2199 static bool getClosestUV (Extrema_GenExtPS& projector,
2200 const gp_Pnt& point,
2203 projector.Perform( point );
2204 if ( projector.IsDone() ) {
2205 double u, v, minVal = DBL_MAX;
2206 for ( int i = projector.NbExt(); i > 0; i-- )
2207 if ( projector.Value( i ) < minVal ) {
2208 minVal = projector.Value( i );
2209 projector.Point( i ).Parameter( u, v );
2211 result.SetCoord( u, v );
2217 //=======================================================================
2219 //purpose : Smooth theElements during theNbIterations or until a worst
2220 // element has aspect ratio <= theTgtAspectRatio.
2221 // Aspect Ratio varies in range [1.0, inf].
2222 // If theElements is empty, the whole mesh is smoothed.
2223 // theFixedNodes contains additionally fixed nodes. Nodes built
2224 // on edges and boundary nodes are always fixed.
2225 //=======================================================================
2227 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2228 set<const SMDS_MeshNode*> & theFixedNodes,
2229 const SmoothMethod theSmoothMethod,
2230 const int theNbIterations,
2231 double theTgtAspectRatio,
2234 myLastCreatedElems.Clear();
2235 myLastCreatedNodes.Clear();
2237 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2239 if ( theTgtAspectRatio < 1.0 )
2240 theTgtAspectRatio = 1.0;
2242 const double disttol = 1.e-16;
2244 SMESH::Controls::AspectRatio aQualityFunc;
2246 SMESHDS_Mesh* aMesh = GetMeshDS();
2248 if ( theElems.empty() ) {
2249 // add all faces to theElems
2250 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2251 while ( fIt->more() ) {
2252 const SMDS_MeshElement* face = fIt->next();
2253 theElems.insert( face );
2256 // get all face ids theElems are on
2257 set< int > faceIdSet;
2258 TIDSortedElemSet::iterator itElem;
2260 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2261 int fId = FindShape( *itElem );
2262 // check that corresponding submesh exists and a shape is face
2264 faceIdSet.find( fId ) == faceIdSet.end() &&
2265 aMesh->MeshElements( fId )) {
2266 TopoDS_Shape F = aMesh->IndexToShape( fId );
2267 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2268 faceIdSet.insert( fId );
2271 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2273 // ===============================================
2274 // smooth elements on each TopoDS_Face separately
2275 // ===============================================
2277 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2278 for ( ; fId != faceIdSet.rend(); ++fId ) {
2279 // get face surface and submesh
2280 Handle(Geom_Surface) surface;
2281 SMESHDS_SubMesh* faceSubMesh = 0;
2283 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2284 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2285 bool isUPeriodic = false, isVPeriodic = false;
2287 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2288 surface = BRep_Tool::Surface( face );
2289 faceSubMesh = aMesh->MeshElements( *fId );
2290 fToler2 = BRep_Tool::Tolerance( face );
2291 fToler2 *= fToler2 * 10.;
2292 isUPeriodic = surface->IsUPeriodic();
2294 vPeriod = surface->UPeriod();
2295 isVPeriodic = surface->IsVPeriodic();
2297 uPeriod = surface->VPeriod();
2298 surface->Bounds( u1, u2, v1, v2 );
2300 // ---------------------------------------------------------
2301 // for elements on a face, find movable and fixed nodes and
2302 // compute UV for them
2303 // ---------------------------------------------------------
2304 bool checkBoundaryNodes = false;
2305 bool isQuadratic = false;
2306 set<const SMDS_MeshNode*> setMovableNodes;
2307 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2308 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2309 list< const SMDS_MeshElement* > elemsOnFace;
2311 Extrema_GenExtPS projector;
2312 GeomAdaptor_Surface surfAdaptor;
2313 if ( !surface.IsNull() ) {
2314 surfAdaptor.Load( surface );
2315 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2317 int nbElemOnFace = 0;
2318 itElem = theElems.begin();
2319 // loop on not yet smoothed elements: look for elems on a face
2320 while ( itElem != theElems.end() ) {
2321 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2322 break; // all elements found
2324 const SMDS_MeshElement* elem = *itElem;
2325 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2326 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2330 elemsOnFace.push_back( elem );
2331 theElems.erase( itElem++ );
2335 isQuadratic = elem->IsQuadratic();
2337 // get movable nodes of elem
2338 const SMDS_MeshNode* node;
2339 SMDS_TypeOfPosition posType;
2340 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2341 int nn = 0, nbn = elem->NbNodes();
2342 if(elem->IsQuadratic())
2344 while ( nn++ < nbn ) {
2345 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2346 const SMDS_PositionPtr& pos = node->GetPosition();
2347 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2348 if (posType != SMDS_TOP_EDGE &&
2349 posType != SMDS_TOP_VERTEX &&
2350 theFixedNodes.find( node ) == theFixedNodes.end())
2352 // check if all faces around the node are on faceSubMesh
2353 // because a node on edge may be bound to face
2354 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2356 if ( faceSubMesh ) {
2357 while ( eIt->more() && all ) {
2358 const SMDS_MeshElement* e = eIt->next();
2359 all = faceSubMesh->Contains( e );
2363 setMovableNodes.insert( node );
2365 checkBoundaryNodes = true;
2367 if ( posType == SMDS_TOP_3DSPACE )
2368 checkBoundaryNodes = true;
2371 if ( surface.IsNull() )
2374 // get nodes to check UV
2375 list< const SMDS_MeshNode* > uvCheckNodes;
2376 itN = elem->nodesIterator();
2377 nn = 0; nbn = elem->NbNodes();
2378 if(elem->IsQuadratic())
2380 while ( nn++ < nbn ) {
2381 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2382 if ( uvMap.find( node ) == uvMap.end() )
2383 uvCheckNodes.push_back( node );
2384 // add nodes of elems sharing node
2385 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2386 // while ( eIt->more() ) {
2387 // const SMDS_MeshElement* e = eIt->next();
2388 // if ( e != elem ) {
2389 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2390 // while ( nIt->more() ) {
2391 // const SMDS_MeshNode* n =
2392 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2393 // if ( uvMap.find( n ) == uvMap.end() )
2394 // uvCheckNodes.push_back( n );
2400 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2401 for ( ; n != uvCheckNodes.end(); ++n ) {
2404 const SMDS_PositionPtr& pos = node->GetPosition();
2405 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2407 switch ( posType ) {
2408 case SMDS_TOP_FACE: {
2409 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2410 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2413 case SMDS_TOP_EDGE: {
2414 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2415 Handle(Geom2d_Curve) pcurve;
2416 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2417 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2418 if ( !pcurve.IsNull() ) {
2419 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2420 uv = pcurve->Value( u ).XY();
2424 case SMDS_TOP_VERTEX: {
2425 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2426 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2427 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2432 // check existing UV
2433 bool project = true;
2434 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2435 double dist1 = DBL_MAX, dist2 = 0;
2436 if ( posType != SMDS_TOP_3DSPACE ) {
2437 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2438 project = dist1 > fToler2;
2440 if ( project ) { // compute new UV
2442 if ( !getClosestUV( projector, pNode, newUV )) {
2443 MESSAGE("Node Projection Failed " << node);
2447 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2449 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2451 if ( posType != SMDS_TOP_3DSPACE )
2452 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2453 if ( dist2 < dist1 )
2457 // store UV in the map
2458 listUV.push_back( uv );
2459 uvMap.insert( make_pair( node, &listUV.back() ));
2461 } // loop on not yet smoothed elements
2463 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2464 checkBoundaryNodes = true;
2466 // fix nodes on mesh boundary
2468 if ( checkBoundaryNodes ) {
2469 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2470 map< NLink, int >::iterator link_nb;
2471 // put all elements links to linkNbMap
2472 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2473 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2474 const SMDS_MeshElement* elem = (*elemIt);
2475 int nbn = elem->NbNodes();
2476 if(elem->IsQuadratic())
2478 // loop on elem links: insert them in linkNbMap
2479 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2480 for ( int iN = 0; iN < nbn; ++iN ) {
2481 curNode = elem->GetNode( iN );
2483 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2484 else link = make_pair( prevNode , curNode );
2486 link_nb = linkNbMap.find( link );
2487 if ( link_nb == linkNbMap.end() )
2488 linkNbMap.insert( make_pair ( link, 1 ));
2493 // remove nodes that are in links encountered only once from setMovableNodes
2494 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2495 if ( link_nb->second == 1 ) {
2496 setMovableNodes.erase( link_nb->first.first );
2497 setMovableNodes.erase( link_nb->first.second );
2502 // -----------------------------------------------------
2503 // for nodes on seam edge, compute one more UV ( uvMap2 );
2504 // find movable nodes linked to nodes on seam and which
2505 // are to be smoothed using the second UV ( uvMap2 )
2506 // -----------------------------------------------------
2508 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2509 if ( !surface.IsNull() ) {
2510 TopExp_Explorer eExp( face, TopAbs_EDGE );
2511 for ( ; eExp.More(); eExp.Next() ) {
2512 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2513 if ( !BRep_Tool::IsClosed( edge, face ))
2515 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2516 if ( !sm ) continue;
2517 // find out which parameter varies for a node on seam
2520 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2521 if ( pcurve.IsNull() ) continue;
2522 uv1 = pcurve->Value( f );
2524 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2525 if ( pcurve.IsNull() ) continue;
2526 uv2 = pcurve->Value( f );
2527 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2529 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2530 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2532 // get nodes on seam and its vertices
2533 list< const SMDS_MeshNode* > seamNodes;
2534 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2535 while ( nSeamIt->more() ) {
2536 const SMDS_MeshNode* node = nSeamIt->next();
2537 if ( !isQuadratic || !IsMedium( node ))
2538 seamNodes.push_back( node );
2540 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2541 for ( ; vExp.More(); vExp.Next() ) {
2542 sm = aMesh->MeshElements( vExp.Current() );
2544 nSeamIt = sm->GetNodes();
2545 while ( nSeamIt->more() )
2546 seamNodes.push_back( nSeamIt->next() );
2549 // loop on nodes on seam
2550 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2551 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2552 const SMDS_MeshNode* nSeam = *noSeIt;
2553 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2554 if ( n_uv == uvMap.end() )
2557 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2558 // set the second UV
2559 listUV.push_back( *n_uv->second );
2560 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2561 if ( uvMap2.empty() )
2562 uvMap2 = uvMap; // copy the uvMap contents
2563 uvMap2[ nSeam ] = &listUV.back();
2565 // collect movable nodes linked to ones on seam in nodesNearSeam
2566 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2567 while ( eIt->more() ) {
2568 const SMDS_MeshElement* e = eIt->next();
2569 int nbUseMap1 = 0, nbUseMap2 = 0;
2570 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2571 int nn = 0, nbn = e->NbNodes();
2572 if(e->IsQuadratic()) nbn = nbn/2;
2573 while ( nn++ < nbn )
2575 const SMDS_MeshNode* n =
2576 static_cast<const SMDS_MeshNode*>( nIt->next() );
2578 setMovableNodes.find( n ) == setMovableNodes.end() )
2580 // add only nodes being closer to uv2 than to uv1
2581 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2582 0.5 * ( n->Y() + nSeam->Y() ),
2583 0.5 * ( n->Z() + nSeam->Z() ));
2585 getClosestUV( projector, pMid, uv );
2586 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2587 nodesNearSeam.insert( n );
2593 // for centroidalSmooth all element nodes must
2594 // be on one side of a seam
2595 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2596 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2598 while ( nn++ < nbn ) {
2599 const SMDS_MeshNode* n =
2600 static_cast<const SMDS_MeshNode*>( nIt->next() );
2601 setMovableNodes.erase( n );
2605 } // loop on nodes on seam
2606 } // loop on edge of a face
2607 } // if ( !face.IsNull() )
2609 if ( setMovableNodes.empty() ) {
2610 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2611 continue; // goto next face
2619 double maxRatio = -1., maxDisplacement = -1.;
2620 set<const SMDS_MeshNode*>::iterator nodeToMove;
2621 for ( it = 0; it < theNbIterations; it++ ) {
2622 maxDisplacement = 0.;
2623 nodeToMove = setMovableNodes.begin();
2624 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2625 const SMDS_MeshNode* node = (*nodeToMove);
2626 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2629 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2630 if ( theSmoothMethod == LAPLACIAN )
2631 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2633 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2635 // node displacement
2636 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2637 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2638 if ( aDispl > maxDisplacement )
2639 maxDisplacement = aDispl;
2641 // no node movement => exit
2642 //if ( maxDisplacement < 1.e-16 ) {
2643 if ( maxDisplacement < disttol ) {
2644 MESSAGE("-- no node movement --");
2648 // check elements quality
2650 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2651 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2652 const SMDS_MeshElement* elem = (*elemIt);
2653 if ( !elem || elem->GetType() != SMDSAbs_Face )
2655 SMESH::Controls::TSequenceOfXYZ aPoints;
2656 if ( aQualityFunc.GetPoints( elem, aPoints )) {
2657 double aValue = aQualityFunc.GetValue( aPoints );
2658 if ( aValue > maxRatio )
2662 if ( maxRatio <= theTgtAspectRatio ) {
2663 MESSAGE("-- quality achived --");
2666 if (it+1 == theNbIterations) {
2667 MESSAGE("-- Iteration limit exceeded --");
2669 } // smoothing iterations
2671 MESSAGE(" Face id: " << *fId <<
2672 " Nb iterstions: " << it <<
2673 " Displacement: " << maxDisplacement <<
2674 " Aspect Ratio " << maxRatio);
2676 // ---------------------------------------
2677 // new nodes positions are computed,
2678 // record movement in DS and set new UV
2679 // ---------------------------------------
2680 nodeToMove = setMovableNodes.begin();
2681 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2682 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2683 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2684 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2685 if ( node_uv != uvMap.end() ) {
2686 gp_XY* uv = node_uv->second;
2688 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2692 // move medium nodes of quadratic elements
2695 SMESH_MesherHelper helper( *GetMesh() );
2696 if ( !face.IsNull() )
2697 helper.SetSubShape( face );
2698 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2699 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2700 const SMDS_QuadraticFaceOfNodes* QF =
2701 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2703 vector<const SMDS_MeshNode*> Ns;
2704 Ns.reserve(QF->NbNodes()+1);
2705 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2706 while ( anIter->more() )
2707 Ns.push_back( anIter->next() );
2708 Ns.push_back( Ns[0] );
2710 for(int i=0; i<QF->NbNodes(); i=i+2) {
2711 if ( !surface.IsNull() ) {
2712 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2713 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2714 gp_XY uv = ( uv1 + uv2 ) / 2.;
2715 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2716 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2719 x = (Ns[i]->X() + Ns[i+2]->X())/2;
2720 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2721 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2723 if( fabs( Ns[i+1]->X() - x ) > disttol ||
2724 fabs( Ns[i+1]->Y() - y ) > disttol ||
2725 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2726 // we have to move i+1 node
2727 aMesh->MoveNode( Ns[i+1], x, y, z );
2734 } // loop on face ids
2738 //=======================================================================
2739 //function : isReverse
2740 //purpose : Return true if normal of prevNodes is not co-directied with
2741 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2742 // iNotSame is where prevNodes and nextNodes are different
2743 //=======================================================================
2745 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2746 vector<const SMDS_MeshNode*> nextNodes,
2750 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2751 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2753 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2754 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2755 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2756 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2758 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2759 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2760 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2761 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2763 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2765 return (vA ^ vB) * vN < 0.0;
2768 //=======================================================================
2770 * \brief Create elements by sweeping an element
2771 * \param elem - element to sweep
2772 * \param newNodesItVec - nodes generated from each node of the element
2773 * \param newElems - generated elements
2774 * \param nbSteps - number of sweeping steps
2775 * \param srcElements - to append elem for each generated element
2777 //=======================================================================
2779 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
2780 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2781 list<const SMDS_MeshElement*>& newElems,
2783 SMESH_SequenceOfElemPtr& srcElements)
2785 SMESHDS_Mesh* aMesh = GetMeshDS();
2787 // Loop on elem nodes:
2788 // find new nodes and detect same nodes indices
2789 int nbNodes = elem->NbNodes();
2790 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2791 vector<const SMDS_MeshNode*> prevNod( nbNodes );
2792 vector<const SMDS_MeshNode*> nextNod( nbNodes );
2793 vector<const SMDS_MeshNode*> midlNod( nbNodes );
2795 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2796 vector<int> sames(nbNodes);
2797 vector<bool> issimple(nbNodes);
2799 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2800 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2801 const SMDS_MeshNode* node = nnIt->first;
2802 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2803 if ( listNewNodes.empty() ) {
2807 issimple[iNode] = (listNewNodes.size()==nbSteps);
2809 itNN[ iNode ] = listNewNodes.begin();
2810 prevNod[ iNode ] = node;
2811 nextNod[ iNode ] = listNewNodes.front();
2812 if( !issimple[iNode] ) {
2813 if ( prevNod[ iNode ] != nextNod [ iNode ])
2814 iNotSameNode = iNode;
2818 sames[nbSame++] = iNode;
2823 //cout<<" nbSame = "<<nbSame<<endl;
2824 if ( nbSame == nbNodes || nbSame > 2) {
2825 //MESSAGE( " Too many same nodes of element " << elem->GetID() );
2826 INFOS( " Too many same nodes of element " << elem->GetID() );
2830 // if( elem->IsQuadratic() && nbSame>0 ) {
2831 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2835 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2836 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2838 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2839 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2840 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2844 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2845 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2846 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2847 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2849 // check element orientation
2851 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2852 //MESSAGE("Reversed elem " << elem );
2856 std::swap( iBeforeSame, iAfterSame );
2859 // make new elements
2860 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
2862 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2863 if(issimple[iNode]) {
2864 nextNod[ iNode ] = *itNN[ iNode ];
2868 if( elem->GetType()==SMDSAbs_Node ) {
2869 // we have to use two nodes
2870 midlNod[ iNode ] = *itNN[ iNode ];
2872 nextNod[ iNode ] = *itNN[ iNode ];
2875 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
2876 // we have to use each second node
2878 nextNod[ iNode ] = *itNN[ iNode ];
2882 // we have to use two nodes
2883 midlNod[ iNode ] = *itNN[ iNode ];
2885 nextNod[ iNode ] = *itNN[ iNode ];
2890 SMDS_MeshElement* aNewElem = 0;
2891 if(!elem->IsPoly()) {
2892 switch ( nbNodes ) {
2896 if ( nbSame == 0 ) {
2898 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2900 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2906 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2907 nextNod[ 1 ], nextNod[ 0 ] );
2909 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2910 nextNod[ iNotSameNode ] );
2914 case 3: { // TRIANGLE or quadratic edge
2915 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2917 if ( nbSame == 0 ) // --- pentahedron
2918 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2919 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2921 else if ( nbSame == 1 ) // --- pyramid
2922 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2923 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2924 nextNod[ iSameNode ]);
2926 else // 2 same nodes: --- tetrahedron
2927 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2928 nextNod[ iNotSameNode ]);
2930 else { // quadratic edge
2931 if(nbSame==0) { // quadratic quadrangle
2932 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2933 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2935 else if(nbSame==1) { // quadratic triangle
2937 return; // medium node on axis
2939 else if(sames[0]==0) {
2940 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2941 nextNod[2], midlNod[1], prevNod[2]);
2943 else { // sames[0]==1
2944 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2945 midlNod[0], nextNod[2], prevNod[2]);
2954 case 4: { // QUADRANGLE
2956 if ( nbSame == 0 ) // --- hexahedron
2957 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2958 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2960 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2961 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2962 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2963 nextNod[ iSameNode ]);
2964 newElems.push_back( aNewElem );
2965 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2966 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
2967 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
2969 else if ( nbSame == 2 ) { // pentahedron
2970 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2971 // iBeforeSame is same too
2972 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2973 nextNod[ iOpposSame ], prevNod[ iSameNode ],
2974 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
2976 // iAfterSame is same too
2977 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2978 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2979 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
2983 case 6: { // quadratic triangle
2984 // create pentahedron with 15 nodes
2986 if(i0>0) { // reversed case
2987 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2988 nextNod[0], nextNod[2], nextNod[1],
2989 prevNod[5], prevNod[4], prevNod[3],
2990 nextNod[5], nextNod[4], nextNod[3],
2991 midlNod[0], midlNod[2], midlNod[1]);
2993 else { // not reversed case
2994 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2995 nextNod[0], nextNod[1], nextNod[2],
2996 prevNod[3], prevNod[4], prevNod[5],
2997 nextNod[3], nextNod[4], nextNod[5],
2998 midlNod[0], midlNod[1], midlNod[2]);
3001 else if(nbSame==1) {
3002 // 2d order pyramid of 13 nodes
3003 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3004 // int n12,int n23,int n34,int n41,
3005 // int n15,int n25,int n35,int n45, int ID);
3007 int n1,n4,n41,n15,n45;
3008 if(i0>0) { // reversed case
3009 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3010 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3016 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3017 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3022 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3023 nextNod[n4], prevNod[n4], prevNod[n5],
3024 midlNod[n1], nextNod[n41],
3025 midlNod[n4], prevNod[n41],
3026 prevNod[n15], nextNod[n15],
3027 nextNod[n45], prevNod[n45]);
3029 else if(nbSame==2) {
3030 // 2d order tetrahedron of 10 nodes
3031 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3032 // int n12,int n23,int n31,
3033 // int n14,int n24,int n34, int ID);
3034 int n1 = iNotSameNode;
3035 int n2,n3,n12,n23,n31;
3036 if(i0>0) { // reversed case
3037 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3038 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3044 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3045 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3050 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3051 prevNod[n12], prevNod[n23], prevNod[n31],
3052 midlNod[n1], nextNod[n12], nextNod[n31]);
3056 case 8: { // quadratic quadrangle
3058 // create hexahedron with 20 nodes
3059 if(i0>0) { // reversed case
3060 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3061 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3062 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3063 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3064 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3066 else { // not reversed case
3067 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3068 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3069 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3070 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3071 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3074 else if(nbSame==1) {
3075 // --- pyramid + pentahedron - can not be created since it is needed
3076 // additional middle node ot the center of face
3077 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3080 else if(nbSame==2) {
3081 // 2d order Pentahedron with 15 nodes
3082 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3083 // int n12,int n23,int n31,int n45,int n56,int n64,
3084 // int n14,int n25,int n36, int ID);
3086 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3087 // iBeforeSame is same too
3094 // iAfterSame is same too
3100 int n12,n45,n14,n25;
3101 if(i0>0) { //reversed case
3113 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3114 prevNod[n4], prevNod[n5], nextNod[n5],
3115 prevNod[n12], midlNod[n2], nextNod[n12],
3116 prevNod[n45], midlNod[n5], nextNod[n45],
3117 prevNod[n14], prevNod[n25], nextNod[n25]);
3122 // realized for extrusion only
3123 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3124 //vector<int> quantities (nbNodes + 2);
3126 //quantities[0] = nbNodes; // bottom of prism
3127 //for (int inode = 0; inode < nbNodes; inode++) {
3128 // polyedre_nodes[inode] = prevNod[inode];
3131 //quantities[1] = nbNodes; // top of prism
3132 //for (int inode = 0; inode < nbNodes; inode++) {
3133 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3136 //for (int iface = 0; iface < nbNodes; iface++) {
3137 // quantities[iface + 2] = 4;
3138 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3139 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3140 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3141 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3142 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3144 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3151 // realized for extrusion only
3152 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3153 vector<int> quantities (nbNodes + 2);
3155 quantities[0] = nbNodes; // bottom of prism
3156 for (int inode = 0; inode < nbNodes; inode++) {
3157 polyedre_nodes[inode] = prevNod[inode];
3160 quantities[1] = nbNodes; // top of prism
3161 for (int inode = 0; inode < nbNodes; inode++) {
3162 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3165 for (int iface = 0; iface < nbNodes; iface++) {
3166 quantities[iface + 2] = 4;
3167 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3168 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3169 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3170 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3171 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3173 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3177 newElems.push_back( aNewElem );
3178 myLastCreatedElems.Append(aNewElem);
3179 srcElements.Append( elem );
3182 // set new prev nodes
3183 for ( iNode = 0; iNode < nbNodes; iNode++ )
3184 prevNod[ iNode ] = nextNod[ iNode ];
3189 //=======================================================================
3191 * \brief Create 1D and 2D elements around swept elements
3192 * \param mapNewNodes - source nodes and ones generated from them
3193 * \param newElemsMap - source elements and ones generated from them
3194 * \param elemNewNodesMap - nodes generated from each node of each element
3195 * \param elemSet - all swept elements
3196 * \param nbSteps - number of sweeping steps
3197 * \param srcElements - to append elem for each generated element
3199 //=======================================================================
3201 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3202 TElemOfElemListMap & newElemsMap,
3203 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3204 TIDSortedElemSet& elemSet,
3206 SMESH_SequenceOfElemPtr& srcElements)
3208 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3209 SMESHDS_Mesh* aMesh = GetMeshDS();
3211 // Find nodes belonging to only one initial element - sweep them to get edges.
3213 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3214 for ( ; nList != mapNewNodes.end(); nList++ ) {
3215 const SMDS_MeshNode* node =
3216 static_cast<const SMDS_MeshNode*>( nList->first );
3217 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3218 int nbInitElems = 0;
3219 const SMDS_MeshElement* el = 0;
3220 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3221 while ( eIt->more() && nbInitElems < 2 ) {
3223 SMDSAbs_ElementType type = el->GetType();
3224 if ( type == SMDSAbs_Volume || type < highType ) continue;
3225 if ( type > highType ) {
3229 if ( elemSet.find(el) != elemSet.end() )
3232 if ( nbInitElems < 2 ) {
3233 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3234 if(!NotCreateEdge) {
3235 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3236 list<const SMDS_MeshElement*> newEdges;
3237 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3242 // Make a ceiling for each element ie an equal element of last new nodes.
3243 // Find free links of faces - make edges and sweep them into faces.
3245 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3246 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3247 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3248 const SMDS_MeshElement* elem = itElem->first;
3249 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3251 if ( elem->GetType() == SMDSAbs_Edge ) {
3252 // create a ceiling edge
3253 if (!elem->IsQuadratic()) {
3254 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3255 vecNewNodes[ 1 ]->second.back())) {
3256 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3257 vecNewNodes[ 1 ]->second.back()));
3258 srcElements.Append( myLastCreatedElems.Last() );
3262 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3263 vecNewNodes[ 1 ]->second.back(),
3264 vecNewNodes[ 2 ]->second.back())) {
3265 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3266 vecNewNodes[ 1 ]->second.back(),
3267 vecNewNodes[ 2 ]->second.back()));
3268 srcElements.Append( myLastCreatedElems.Last() );
3272 if ( elem->GetType() != SMDSAbs_Face )
3275 if(itElem->second.size()==0) continue;
3277 bool hasFreeLinks = false;
3279 TIDSortedElemSet avoidSet;
3280 avoidSet.insert( elem );
3282 set<const SMDS_MeshNode*> aFaceLastNodes;
3283 int iNode, nbNodes = vecNewNodes.size();
3284 if(!elem->IsQuadratic()) {
3285 // loop on the face nodes
3286 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3287 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3288 // look for free links of the face
3289 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3290 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3291 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3292 // check if a link is free
3293 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3294 hasFreeLinks = true;
3295 // make an edge and a ceiling for a new edge
3296 if ( !aMesh->FindEdge( n1, n2 )) {
3297 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3298 srcElements.Append( myLastCreatedElems.Last() );
3300 n1 = vecNewNodes[ iNode ]->second.back();
3301 n2 = vecNewNodes[ iNext ]->second.back();
3302 if ( !aMesh->FindEdge( n1, n2 )) {
3303 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3304 srcElements.Append( myLastCreatedElems.Last() );
3309 else { // elem is quadratic face
3310 int nbn = nbNodes/2;
3311 for ( iNode = 0; iNode < nbn; iNode++ ) {
3312 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3313 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3314 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3315 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3316 // check if a link is free
3317 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3318 hasFreeLinks = true;
3319 // make an edge and a ceiling for a new edge
3321 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3322 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3323 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3324 srcElements.Append( myLastCreatedElems.Last() );
3326 n1 = vecNewNodes[ iNode ]->second.back();
3327 n2 = vecNewNodes[ iNext ]->second.back();
3328 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3329 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3330 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3331 srcElements.Append( myLastCreatedElems.Last() );
3335 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3336 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3340 // sweep free links into faces
3342 if ( hasFreeLinks ) {
3343 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3344 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3346 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3347 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3348 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3349 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3351 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3352 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3354 while ( iVol++ < volNb ) v++;
3355 // find indices of free faces of a volume and their source edges
3356 list< int > freeInd;
3357 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3358 SMDS_VolumeTool vTool( *v );
3359 int iF, nbF = vTool.NbFaces();
3360 for ( iF = 0; iF < nbF; iF ++ ) {
3361 if (vTool.IsFreeFace( iF ) &&
3362 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3363 initNodeSet != faceNodeSet) // except an initial face
3365 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3367 freeInd.push_back( iF );
3368 // find source edge of a free face iF
3369 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3370 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3371 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3372 initNodeSet.begin(), initNodeSet.end(),
3373 commonNodes.begin());
3374 if ( (*v)->IsQuadratic() )
3375 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3377 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3379 if ( !srcEdges.back() )
3381 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3382 << iF << " of volume #" << vTool.ID() << endl;
3387 if ( freeInd.empty() )
3390 // create faces for all steps;
3391 // if such a face has been already created by sweep of edge,
3392 // assure that its orientation is OK
3393 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3395 vTool.SetExternalNormal();
3396 list< int >::iterator ind = freeInd.begin();
3397 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3398 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3400 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3401 int nbn = vTool.NbFaceNodes( *ind );
3403 case 3: { ///// triangle
3404 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3406 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3407 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3408 aMesh->ChangeElementNodes( f, nodes, nbn );
3411 case 4: { ///// quadrangle
3412 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3414 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3415 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3416 aMesh->ChangeElementNodes( f, nodes, nbn );
3420 if( (*v)->IsQuadratic() ) {
3421 if(nbn==6) { /////// quadratic triangle
3422 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3423 nodes[1], nodes[3], nodes[5] );
3425 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3426 nodes[1], nodes[3], nodes[5]));
3428 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3429 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3430 tmpnodes[0] = nodes[0];
3431 tmpnodes[1] = nodes[2];
3432 tmpnodes[2] = nodes[4];
3433 tmpnodes[3] = nodes[1];
3434 tmpnodes[4] = nodes[3];
3435 tmpnodes[5] = nodes[5];
3436 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3439 else { /////// quadratic quadrangle
3440 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3441 nodes[1], nodes[3], nodes[5], nodes[7] );
3443 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3444 nodes[1], nodes[3], nodes[5], nodes[7]));
3446 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3447 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3448 tmpnodes[0] = nodes[0];
3449 tmpnodes[1] = nodes[2];
3450 tmpnodes[2] = nodes[4];
3451 tmpnodes[3] = nodes[6];
3452 tmpnodes[4] = nodes[1];
3453 tmpnodes[5] = nodes[3];
3454 tmpnodes[6] = nodes[5];
3455 tmpnodes[7] = nodes[7];
3456 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3460 else { //////// polygon
3461 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3462 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3464 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3465 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3466 aMesh->ChangeElementNodes( f, nodes, nbn );
3469 while ( srcElements.Length() < myLastCreatedElems.Length() )
3470 srcElements.Append( *srcEdge );
3472 } // loop on free faces
3474 // go to the next volume
3476 while ( iVol++ < nbVolumesByStep ) v++;
3479 } // sweep free links into faces
3481 // Make a ceiling face with a normal external to a volume
3483 SMDS_VolumeTool lastVol( itElem->second.back() );
3485 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3487 lastVol.SetExternalNormal();
3488 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3489 int nbn = lastVol.NbFaceNodes( iF );
3492 if (!hasFreeLinks ||
3493 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3494 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3497 if (!hasFreeLinks ||
3498 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3499 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3502 if(itElem->second.back()->IsQuadratic()) {
3504 if (!hasFreeLinks ||
3505 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3506 nodes[1], nodes[3], nodes[5]) ) {
3507 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3508 nodes[1], nodes[3], nodes[5]));
3512 if (!hasFreeLinks ||
3513 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3514 nodes[1], nodes[3], nodes[5], nodes[7]) )
3515 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3516 nodes[1], nodes[3], nodes[5], nodes[7]));
3520 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3521 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3522 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3526 while ( srcElements.Length() < myLastCreatedElems.Length() )
3527 srcElements.Append( myLastCreatedElems.Last() );
3529 } // loop on swept elements
3532 //=======================================================================
3533 //function : RotationSweep
3535 //=======================================================================
3537 SMESH_MeshEditor::PGroupIDs
3538 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3539 const gp_Ax1& theAxis,
3540 const double theAngle,
3541 const int theNbSteps,
3542 const double theTol,
3543 const bool theMakeGroups,
3544 const bool theMakeWalls)
3546 myLastCreatedElems.Clear();
3547 myLastCreatedNodes.Clear();
3549 // source elements for each generated one
3550 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3552 MESSAGE( "RotationSweep()");
3554 aTrsf.SetRotation( theAxis, theAngle );
3556 aTrsf2.SetRotation( theAxis, theAngle/2. );
3558 gp_Lin aLine( theAxis );
3559 double aSqTol = theTol * theTol;
3561 SMESHDS_Mesh* aMesh = GetMeshDS();
3563 TNodeOfNodeListMap mapNewNodes;
3564 TElemOfVecOfNnlmiMap mapElemNewNodes;
3565 TElemOfElemListMap newElemsMap;
3568 TIDSortedElemSet::iterator itElem;
3569 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3570 const SMDS_MeshElement* elem = *itElem;
3571 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3573 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3574 newNodesItVec.reserve( elem->NbNodes() );
3576 // loop on elem nodes
3577 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3578 while ( itN->more() ) {
3579 // check if a node has been already sweeped
3580 const SMDS_MeshNode* node = cast2Node( itN->next() );
3582 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3584 aXYZ.Coord( coord[0], coord[1], coord[2] );
3585 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3587 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3588 if ( nIt == mapNewNodes.end() ) {
3589 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3590 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3593 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3595 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3596 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3597 const SMDS_MeshNode * newNode = node;
3598 for ( int i = 0; i < theNbSteps; i++ ) {
3600 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3602 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3603 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3604 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3605 myLastCreatedNodes.Append(newNode);
3606 srcNodes.Append( node );
3607 listNewNodes.push_back( newNode );
3608 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3609 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3612 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3614 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3615 myLastCreatedNodes.Append(newNode);
3616 srcNodes.Append( node );
3617 listNewNodes.push_back( newNode );
3620 listNewNodes.push_back( newNode );
3621 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3622 listNewNodes.push_back( newNode );
3629 // if current elem is quadratic and current node is not medium
3630 // we have to check - may be it is needed to insert additional nodes
3631 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3632 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3633 if(listNewNodes.size()==theNbSteps) {
3634 listNewNodes.clear();
3636 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3638 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3639 const SMDS_MeshNode * newNode = node;
3641 for(int i = 0; i<theNbSteps; i++) {
3642 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3643 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3644 cout<<" 3 AddNode: "<<newNode;
3645 myLastCreatedNodes.Append(newNode);
3646 listNewNodes.push_back( newNode );
3647 srcNodes.Append( node );
3648 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3649 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3650 cout<<" 4 AddNode: "<<newNode;
3651 myLastCreatedNodes.Append(newNode);
3652 srcNodes.Append( node );
3653 listNewNodes.push_back( newNode );
3657 listNewNodes.push_back( newNode );
3663 newNodesItVec.push_back( nIt );
3665 // make new elements
3666 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3670 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3672 PGroupIDs newGroupIDs;
3673 if ( theMakeGroups )
3674 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3680 //=======================================================================
3681 //function : CreateNode
3683 //=======================================================================
3684 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3687 const double tolnode,
3688 SMESH_SequenceOfNode& aNodes)
3690 myLastCreatedElems.Clear();
3691 myLastCreatedNodes.Clear();
3694 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3696 // try to search in sequence of existing nodes
3697 // if aNodes.Length()>0 we 'nave to use given sequence
3698 // else - use all nodes of mesh
3699 if(aNodes.Length()>0) {
3701 for(i=1; i<=aNodes.Length(); i++) {
3702 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3703 if(P1.Distance(P2)<tolnode)
3704 return aNodes.Value(i);
3708 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3709 while(itn->more()) {
3710 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3711 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3712 if(P1.Distance(P2)<tolnode)
3717 // create new node and return it
3718 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3719 myLastCreatedNodes.Append(NewNode);
3724 //=======================================================================
3725 //function : ExtrusionSweep
3727 //=======================================================================
3729 SMESH_MeshEditor::PGroupIDs
3730 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3731 const gp_Vec& theStep,
3732 const int theNbSteps,
3733 TElemOfElemListMap& newElemsMap,
3734 const bool theMakeGroups,
3736 const double theTolerance)
3738 ExtrusParam aParams;
3739 aParams.myDir = gp_Dir(theStep);
3740 aParams.myNodes.Clear();
3741 aParams.mySteps = new TColStd_HSequenceOfReal;
3743 for(i=1; i<=theNbSteps; i++)
3744 aParams.mySteps->Append(theStep.Magnitude());
3747 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3751 //=======================================================================
3752 //function : ExtrusionSweep
3754 //=======================================================================
3756 SMESH_MeshEditor::PGroupIDs
3757 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3758 ExtrusParam& theParams,
3759 TElemOfElemListMap& newElemsMap,
3760 const bool theMakeGroups,
3762 const double theTolerance)
3764 myLastCreatedElems.Clear();
3765 myLastCreatedNodes.Clear();
3767 // source elements for each generated one
3768 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3770 SMESHDS_Mesh* aMesh = GetMeshDS();
3772 int nbsteps = theParams.mySteps->Length();
3774 TNodeOfNodeListMap mapNewNodes;
3775 //TNodeOfNodeVecMap mapNewNodes;
3776 TElemOfVecOfNnlmiMap mapElemNewNodes;
3777 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3780 TIDSortedElemSet::iterator itElem;
3781 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3782 // check element type
3783 const SMDS_MeshElement* elem = *itElem;
3784 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3787 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3788 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3789 newNodesItVec.reserve( elem->NbNodes() );
3791 // loop on elem nodes
3792 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3793 while ( itN->more() )
3795 // check if a node has been already sweeped
3796 const SMDS_MeshNode* node = cast2Node( itN->next() );
3797 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3798 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3799 if ( nIt == mapNewNodes.end() ) {
3800 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3801 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3802 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3803 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3804 //vecNewNodes.reserve(nbsteps);
3807 double coord[] = { node->X(), node->Y(), node->Z() };
3808 //int nbsteps = theParams.mySteps->Length();
3809 for ( int i = 0; i < nbsteps; i++ ) {
3810 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3811 // create additional node
3812 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3813 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3814 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3815 if( theFlags & EXTRUSION_FLAG_SEW ) {
3816 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3817 theTolerance, theParams.myNodes);
3818 listNewNodes.push_back( newNode );
3821 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3822 myLastCreatedNodes.Append(newNode);
3823 srcNodes.Append( node );
3824 listNewNodes.push_back( newNode );
3827 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3828 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3829 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3830 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3831 if( theFlags & EXTRUSION_FLAG_SEW ) {
3832 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3833 theTolerance, theParams.myNodes);
3834 listNewNodes.push_back( newNode );
3835 //vecNewNodes[i]=newNode;
3838 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3839 myLastCreatedNodes.Append(newNode);
3840 srcNodes.Append( node );
3841 listNewNodes.push_back( newNode );
3842 //vecNewNodes[i]=newNode;
3847 // if current elem is quadratic and current node is not medium
3848 // we have to check - may be it is needed to insert additional nodes
3849 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3850 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3851 if(listNewNodes.size()==nbsteps) {
3852 listNewNodes.clear();
3853 double coord[] = { node->X(), node->Y(), node->Z() };
3854 for ( int i = 0; i < nbsteps; i++ ) {
3855 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3856 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3857 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3858 if( theFlags & EXTRUSION_FLAG_SEW ) {
3859 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3860 theTolerance, theParams.myNodes);
3861 listNewNodes.push_back( newNode );
3864 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3865 myLastCreatedNodes.Append(newNode);
3866 srcNodes.Append( node );
3867 listNewNodes.push_back( newNode );
3869 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3870 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3871 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3872 if( theFlags & EXTRUSION_FLAG_SEW ) {
3873 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3874 theTolerance, theParams.myNodes);
3875 listNewNodes.push_back( newNode );
3878 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3879 myLastCreatedNodes.Append(newNode);
3880 srcNodes.Append( node );
3881 listNewNodes.push_back( newNode );
3887 newNodesItVec.push_back( nIt );
3889 // make new elements
3890 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
3893 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3894 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
3896 PGroupIDs newGroupIDs;
3897 if ( theMakeGroups )
3898 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
3904 //=======================================================================
3905 //class : SMESH_MeshEditor_PathPoint
3906 //purpose : auxiliary class
3907 //=======================================================================
3908 class SMESH_MeshEditor_PathPoint {
3910 SMESH_MeshEditor_PathPoint() {
3911 myPnt.SetCoord(99., 99., 99.);
3912 myTgt.SetCoord(1.,0.,0.);
3916 void SetPnt(const gp_Pnt& aP3D){
3919 void SetTangent(const gp_Dir& aTgt){
3922 void SetAngle(const double& aBeta){
3925 void SetParameter(const double& aPrm){
3928 const gp_Pnt& Pnt()const{
3931 const gp_Dir& Tangent()const{
3934 double Angle()const{
3937 double Parameter()const{
3949 //=======================================================================
3950 //function : ExtrusionAlongTrack
3952 //=======================================================================
3953 SMESH_MeshEditor::Extrusion_Error
3954 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3955 SMESH_subMesh* theTrack,
3956 const SMDS_MeshNode* theN1,
3957 const bool theHasAngles,
3958 list<double>& theAngles,
3959 const bool theLinearVariation,
3960 const bool theHasRefPoint,
3961 const gp_Pnt& theRefPoint,
3962 const bool theMakeGroups)
3964 myLastCreatedElems.Clear();
3965 myLastCreatedNodes.Clear();
3968 std::list<double> aPrms;
3969 TIDSortedElemSet::iterator itElem;
3972 TopoDS_Edge aTrackEdge;
3973 TopoDS_Vertex aV1, aV2;
3975 SMDS_ElemIteratorPtr aItE;
3976 SMDS_NodeIteratorPtr aItN;
3977 SMDSAbs_ElementType aTypeE;
3979 TNodeOfNodeListMap mapNewNodes;
3982 aNbE = theElements.size();
3985 return EXTR_NO_ELEMENTS;
3987 // 1.1 Track Pattern
3990 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
3992 aItE = pSubMeshDS->GetElements();
3993 while ( aItE->more() ) {
3994 const SMDS_MeshElement* pE = aItE->next();
3995 aTypeE = pE->GetType();
3996 // Pattern must contain links only
3997 if ( aTypeE != SMDSAbs_Edge )
3998 return EXTR_PATH_NOT_EDGE;
4001 list<SMESH_MeshEditor_PathPoint> fullList;
4003 const TopoDS_Shape& aS = theTrack->GetSubShape();
4004 // Sub shape for the Pattern must be an Edge or Wire
4005 if( aS.ShapeType() == TopAbs_EDGE ) {
4006 aTrackEdge = TopoDS::Edge( aS );
4007 // the Edge must not be degenerated
4008 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4009 return EXTR_BAD_PATH_SHAPE;
4010 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4011 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4012 const SMDS_MeshNode* aN1 = aItN->next();
4013 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4014 const SMDS_MeshNode* aN2 = aItN->next();
4015 // starting node must be aN1 or aN2
4016 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4017 return EXTR_BAD_STARTING_NODE;
4018 aItN = pSubMeshDS->GetNodes();
4019 while ( aItN->more() ) {
4020 const SMDS_MeshNode* pNode = aItN->next();
4021 const SMDS_EdgePosition* pEPos =
4022 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4023 double aT = pEPos->GetUParameter();
4024 aPrms.push_back( aT );
4026 //Extrusion_Error err =
4027 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4029 else if( aS.ShapeType() == TopAbs_WIRE ) {
4030 list< SMESH_subMesh* > LSM;
4031 TopTools_SequenceOfShape Edges;
4032 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4033 while(itSM->more()) {
4034 SMESH_subMesh* SM = itSM->next();
4036 const TopoDS_Shape& aS = SM->GetSubShape();
4039 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4040 int startNid = theN1->GetID();
4041 TColStd_MapOfInteger UsedNums;
4042 int NbEdges = Edges.Length();
4044 for(; i<=NbEdges; i++) {
4046 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4047 for(; itLSM!=LSM.end(); itLSM++) {
4049 if(UsedNums.Contains(k)) continue;
4050 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4051 SMESH_subMesh* locTrack = *itLSM;
4052 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4053 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4054 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4055 const SMDS_MeshNode* aN1 = aItN->next();
4056 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4057 const SMDS_MeshNode* aN2 = aItN->next();
4058 // starting node must be aN1 or aN2
4059 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4060 // 2. Collect parameters on the track edge
4062 aItN = locMeshDS->GetNodes();
4063 while ( aItN->more() ) {
4064 const SMDS_MeshNode* pNode = aItN->next();
4065 const SMDS_EdgePosition* pEPos =
4066 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4067 double aT = pEPos->GetUParameter();
4068 aPrms.push_back( aT );
4070 list<SMESH_MeshEditor_PathPoint> LPP;
4071 //Extrusion_Error err =
4072 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4073 LLPPs.push_back(LPP);
4075 // update startN for search following egde
4076 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4077 else startNid = aN1->GetID();
4081 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4082 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4083 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4084 for(; itPP!=firstList.end(); itPP++) {
4085 fullList.push_back( *itPP );
4087 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4088 fullList.pop_back();
4090 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4091 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4092 itPP = currList.begin();
4093 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4094 gp_Dir D1 = PP1.Tangent();
4095 gp_Dir D2 = PP2.Tangent();
4096 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4097 (D1.Z()+D2.Z())/2 ) );
4098 PP1.SetTangent(Dnew);
4099 fullList.push_back(PP1);
4101 for(; itPP!=firstList.end(); itPP++) {
4102 fullList.push_back( *itPP );
4104 PP1 = fullList.back();
4105 fullList.pop_back();
4107 // if wire not closed
4108 fullList.push_back(PP1);
4112 return EXTR_BAD_PATH_SHAPE;
4115 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4116 theHasRefPoint, theRefPoint, theMakeGroups);
4120 //=======================================================================
4121 //function : ExtrusionAlongTrack
4123 //=======================================================================
4124 SMESH_MeshEditor::Extrusion_Error
4125 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4126 SMESH_Mesh* theTrack,
4127 const SMDS_MeshNode* theN1,
4128 const bool theHasAngles,
4129 list<double>& theAngles,
4130 const bool theLinearVariation,
4131 const bool theHasRefPoint,
4132 const gp_Pnt& theRefPoint,
4133 const bool theMakeGroups)
4135 myLastCreatedElems.Clear();
4136 myLastCreatedNodes.Clear();
4139 std::list<double> aPrms;
4140 TIDSortedElemSet::iterator itElem;
4143 TopoDS_Edge aTrackEdge;
4144 TopoDS_Vertex aV1, aV2;
4146 SMDS_ElemIteratorPtr aItE;
4147 SMDS_NodeIteratorPtr aItN;
4148 SMDSAbs_ElementType aTypeE;
4150 TNodeOfNodeListMap mapNewNodes;
4153 aNbE = theElements.size();
4156 return EXTR_NO_ELEMENTS;
4158 // 1.1 Track Pattern
4161 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4163 aItE = pMeshDS->elementsIterator();
4164 while ( aItE->more() ) {
4165 const SMDS_MeshElement* pE = aItE->next();
4166 aTypeE = pE->GetType();
4167 // Pattern must contain links only
4168 if ( aTypeE != SMDSAbs_Edge )
4169 return EXTR_PATH_NOT_EDGE;
4172 list<SMESH_MeshEditor_PathPoint> fullList;
4174 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4175 // Sub shape for the Pattern must be an Edge or Wire
4176 if( aS.ShapeType() == TopAbs_EDGE ) {
4177 aTrackEdge = TopoDS::Edge( aS );
4178 // the Edge must not be degenerated
4179 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4180 return EXTR_BAD_PATH_SHAPE;
4181 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4182 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4183 const SMDS_MeshNode* aN1 = aItN->next();
4184 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4185 const SMDS_MeshNode* aN2 = aItN->next();
4186 // starting node must be aN1 or aN2
4187 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4188 return EXTR_BAD_STARTING_NODE;
4189 aItN = pMeshDS->nodesIterator();
4190 while ( aItN->more() ) {
4191 const SMDS_MeshNode* pNode = aItN->next();
4192 if( pNode==aN1 || pNode==aN2 ) continue;
4193 const SMDS_EdgePosition* pEPos =
4194 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4195 double aT = pEPos->GetUParameter();
4196 aPrms.push_back( aT );
4198 //Extrusion_Error err =
4199 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4201 else if( aS.ShapeType() == TopAbs_WIRE ) {
4202 list< SMESH_subMesh* > LSM;
4203 TopTools_SequenceOfShape Edges;
4204 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4205 for(; eExp.More(); eExp.Next()) {
4206 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4207 if( BRep_Tool::Degenerated(E) ) continue;
4208 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4214 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4215 int startNid = theN1->GetID();
4216 TColStd_MapOfInteger UsedNums;
4217 int NbEdges = Edges.Length();
4219 for(; i<=NbEdges; i++) {
4221 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4222 for(; itLSM!=LSM.end(); itLSM++) {
4224 if(UsedNums.Contains(k)) continue;
4225 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4226 SMESH_subMesh* locTrack = *itLSM;
4227 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4228 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4229 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4230 const SMDS_MeshNode* aN1 = aItN->next();
4231 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4232 const SMDS_MeshNode* aN2 = aItN->next();
4233 // starting node must be aN1 or aN2
4234 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4235 // 2. Collect parameters on the track edge
4237 aItN = locMeshDS->GetNodes();
4238 while ( aItN->more() ) {
4239 const SMDS_MeshNode* pNode = aItN->next();
4240 const SMDS_EdgePosition* pEPos =
4241 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4242 double aT = pEPos->GetUParameter();
4243 aPrms.push_back( aT );
4245 list<SMESH_MeshEditor_PathPoint> LPP;
4246 //Extrusion_Error err =
4247 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4248 LLPPs.push_back(LPP);
4250 // update startN for search following egde
4251 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4252 else startNid = aN1->GetID();
4256 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4257 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4258 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4259 for(; itPP!=firstList.end(); itPP++) {
4260 fullList.push_back( *itPP );
4262 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4263 fullList.pop_back();
4265 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4266 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4267 itPP = currList.begin();
4268 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4269 gp_Pnt P1 = PP1.Pnt();
4270 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4271 gp_Pnt P2 = PP2.Pnt();
4272 gp_Dir D1 = PP1.Tangent();
4273 gp_Dir D2 = PP2.Tangent();
4274 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4275 (D1.Z()+D2.Z())/2 ) );
4276 PP1.SetTangent(Dnew);
4277 fullList.push_back(PP1);
4279 for(; itPP!=currList.end(); itPP++) {
4280 fullList.push_back( *itPP );
4282 PP1 = fullList.back();
4283 fullList.pop_back();
4285 // if wire not closed
4286 fullList.push_back(PP1);
4290 return EXTR_BAD_PATH_SHAPE;
4293 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4294 theHasRefPoint, theRefPoint, theMakeGroups);
4298 //=======================================================================
4299 //function : MakeEdgePathPoints
4300 //purpose : auxilary for ExtrusionAlongTrack
4301 //=======================================================================
4302 SMESH_MeshEditor::Extrusion_Error
4303 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4304 const TopoDS_Edge& aTrackEdge,
4306 list<SMESH_MeshEditor_PathPoint>& LPP)
4308 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4310 aTolVec2=aTolVec*aTolVec;
4312 TopoDS_Vertex aV1, aV2;
4313 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4314 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4315 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4316 // 2. Collect parameters on the track edge
4317 aPrms.push_front( aT1 );
4318 aPrms.push_back( aT2 );
4321 if( FirstIsStart ) {
4332 SMESH_MeshEditor_PathPoint aPP;
4333 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4334 std::list<double>::iterator aItD = aPrms.begin();
4335 for(; aItD != aPrms.end(); ++aItD) {
4339 aC3D->D1( aT, aP3D, aVec );
4340 aL2 = aVec.SquareMagnitude();
4341 if ( aL2 < aTolVec2 )
4342 return EXTR_CANT_GET_TANGENT;
4343 gp_Dir aTgt( aVec );
4345 aPP.SetTangent( aTgt );
4346 aPP.SetParameter( aT );
4353 //=======================================================================
4354 //function : MakeExtrElements
4355 //purpose : auxilary for ExtrusionAlongTrack
4356 //=======================================================================
4357 SMESH_MeshEditor::Extrusion_Error
4358 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4359 list<SMESH_MeshEditor_PathPoint>& fullList,
4360 const bool theHasAngles,
4361 list<double>& theAngles,
4362 const bool theLinearVariation,
4363 const bool theHasRefPoint,
4364 const gp_Pnt& theRefPoint,
4365 const bool theMakeGroups)
4367 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4368 int aNbTP = fullList.size();
4369 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4371 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4372 LinearAngleVariation(aNbTP-1, theAngles);
4374 vector<double> aAngles( aNbTP );
4376 for(; j<aNbTP; ++j) {
4379 if ( theHasAngles ) {
4381 std::list<double>::iterator aItD = theAngles.begin();
4382 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4384 aAngles[j] = anAngle;
4387 // fill vector of path points with angles
4388 //aPPs.resize(fullList.size());
4390 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4391 for(; itPP!=fullList.end(); itPP++) {
4393 SMESH_MeshEditor_PathPoint PP = *itPP;
4394 PP.SetAngle(aAngles[j]);
4398 TNodeOfNodeListMap mapNewNodes;
4399 TElemOfVecOfNnlmiMap mapElemNewNodes;
4400 TElemOfElemListMap newElemsMap;
4401 TIDSortedElemSet::iterator itElem;
4404 SMDSAbs_ElementType aTypeE;
4405 // source elements for each generated one
4406 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4408 // 3. Center of rotation aV0
4409 gp_Pnt aV0 = theRefPoint;
4411 if ( !theHasRefPoint ) {
4413 aGC.SetCoord( 0.,0.,0. );
4415 itElem = theElements.begin();
4416 for ( ; itElem != theElements.end(); itElem++ ) {
4417 const SMDS_MeshElement* elem = *itElem;
4419 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4420 while ( itN->more() ) {
4421 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4426 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4427 list<const SMDS_MeshNode*> aLNx;
4428 mapNewNodes[node] = aLNx;
4430 gp_XYZ aXYZ( aX, aY, aZ );
4438 } // if (!theHasRefPoint) {
4439 mapNewNodes.clear();
4441 // 4. Processing the elements
4442 SMESHDS_Mesh* aMesh = GetMeshDS();
4444 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4445 // check element type
4446 const SMDS_MeshElement* elem = *itElem;
4447 aTypeE = elem->GetType();
4448 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4451 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4452 newNodesItVec.reserve( elem->NbNodes() );
4454 // loop on elem nodes
4456 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4457 while ( itN->more() )
4460 // check if a node has been already processed
4461 const SMDS_MeshNode* node =
4462 static_cast<const SMDS_MeshNode*>( itN->next() );
4463 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4464 if ( nIt == mapNewNodes.end() ) {
4465 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4466 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4469 aX = node->X(); aY = node->Y(); aZ = node->Z();
4471 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4472 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4473 gp_Ax1 anAx1, anAxT1T0;
4474 gp_Dir aDT1x, aDT0x, aDT1T0;
4479 aPN0.SetCoord(aX, aY, aZ);
4481 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4483 aDT0x= aPP0.Tangent();
4484 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4486 for ( j = 1; j < aNbTP; ++j ) {
4487 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4489 aDT1x = aPP1.Tangent();
4490 aAngle1x = aPP1.Angle();
4492 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4494 gp_Vec aV01x( aP0x, aP1x );
4495 aTrsf.SetTranslation( aV01x );
4498 aV1x = aV0x.Transformed( aTrsf );
4499 aPN1 = aPN0.Transformed( aTrsf );
4501 // rotation 1 [ T1,T0 ]
4502 aAngleT1T0=-aDT1x.Angle( aDT0x );
4503 if (fabs(aAngleT1T0) > aTolAng) {
4505 anAxT1T0.SetLocation( aV1x );
4506 anAxT1T0.SetDirection( aDT1T0 );
4507 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4509 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4513 if ( theHasAngles ) {
4514 anAx1.SetLocation( aV1x );
4515 anAx1.SetDirection( aDT1x );
4516 aTrsfRot.SetRotation( anAx1, aAngle1x );
4518 aPN1 = aPN1.Transformed( aTrsfRot );
4522 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4523 // create additional node
4524 double x = ( aPN1.X() + aPN0.X() )/2.;
4525 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4526 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4527 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4528 myLastCreatedNodes.Append(newNode);
4529 srcNodes.Append( node );
4530 listNewNodes.push_back( newNode );
4535 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4536 myLastCreatedNodes.Append(newNode);
4537 srcNodes.Append( node );
4538 listNewNodes.push_back( newNode );
4548 // if current elem is quadratic and current node is not medium
4549 // we have to check - may be it is needed to insert additional nodes
4550 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4551 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4552 if(listNewNodes.size()==aNbTP-1) {
4553 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4554 gp_XYZ P(node->X(), node->Y(), node->Z());
4555 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4557 for(i=0; i<aNbTP-1; i++) {
4558 const SMDS_MeshNode* N = *it;
4559 double x = ( N->X() + P.X() )/2.;
4560 double y = ( N->Y() + P.Y() )/2.;
4561 double z = ( N->Z() + P.Z() )/2.;
4562 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4563 srcNodes.Append( node );
4564 myLastCreatedNodes.Append(newN);
4567 P = gp_XYZ(N->X(),N->Y(),N->Z());
4569 listNewNodes.clear();
4570 for(i=0; i<2*(aNbTP-1); i++) {
4571 listNewNodes.push_back(aNodes[i]);
4577 newNodesItVec.push_back( nIt );
4579 // make new elements
4580 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4581 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4582 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4585 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4587 if ( theMakeGroups )
4588 generateGroups( srcNodes, srcElems, "extruded");
4594 //=======================================================================
4595 //function : LinearAngleVariation
4596 //purpose : auxilary for ExtrusionAlongTrack
4597 //=======================================================================
4598 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4599 list<double>& Angles)
4601 int nbAngles = Angles.size();
4602 if( nbSteps > nbAngles ) {
4603 vector<double> theAngles(nbAngles);
4604 list<double>::iterator it = Angles.begin();
4606 for(; it!=Angles.end(); it++) {
4608 theAngles[i] = (*it);
4611 double rAn2St = double( nbAngles ) / double( nbSteps );
4612 double angPrev = 0, angle;
4613 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4614 double angCur = rAn2St * ( iSt+1 );
4615 double angCurFloor = floor( angCur );
4616 double angPrevFloor = floor( angPrev );
4617 if ( angPrevFloor == angCurFloor )
4618 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4620 int iP = int( angPrevFloor );
4621 double angPrevCeil = ceil(angPrev);
4622 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4624 int iC = int( angCurFloor );
4625 if ( iC < nbAngles )
4626 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4628 iP = int( angPrevCeil );
4630 angle += theAngles[ iC ];
4632 res.push_back(angle);
4637 for(; it!=res.end(); it++)
4638 Angles.push_back( *it );
4643 //=======================================================================
4644 //function : Transform
4646 //=======================================================================
4648 SMESH_MeshEditor::PGroupIDs
4649 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4650 const gp_Trsf& theTrsf,
4652 const bool theMakeGroups,
4653 SMESH_Mesh* theTargetMesh)
4655 myLastCreatedElems.Clear();
4656 myLastCreatedNodes.Clear();
4658 bool needReverse = false;
4659 string groupPostfix;
4660 switch ( theTrsf.Form() ) {
4665 groupPostfix = "mirrored";
4668 groupPostfix = "rotated";
4670 case gp_Translation:
4671 groupPostfix = "translated";
4674 groupPostfix = "scaled";
4677 needReverse = false;
4678 groupPostfix = "transformed";
4681 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4682 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4683 SMESHDS_Mesh* aMesh = GetMeshDS();
4686 // map old node to new one
4687 TNodeNodeMap nodeMap;
4689 // elements sharing moved nodes; those of them which have all
4690 // nodes mirrored but are not in theElems are to be reversed
4691 TIDSortedElemSet inverseElemSet;
4693 // source elements for each generated one
4694 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4697 TIDSortedElemSet::iterator itElem;
4698 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4699 const SMDS_MeshElement* elem = *itElem;
4703 // loop on elem nodes
4704 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4705 while ( itN->more() ) {
4707 // check if a node has been already transformed
4708 const SMDS_MeshNode* node = cast2Node( itN->next() );
4709 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4710 nodeMap.insert( make_pair ( node, node ));
4711 if ( !n2n_isnew.second )
4715 coord[0] = node->X();
4716 coord[1] = node->Y();
4717 coord[2] = node->Z();
4718 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4719 if ( theTargetMesh ) {
4720 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4721 n2n_isnew.first->second = newNode;
4722 myLastCreatedNodes.Append(newNode);
4723 srcNodes.Append( node );
4725 else if ( theCopy ) {
4726 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4727 n2n_isnew.first->second = newNode;
4728 myLastCreatedNodes.Append(newNode);
4729 srcNodes.Append( node );
4732 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4733 // node position on shape becomes invalid
4734 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4735 ( SMDS_SpacePosition::originSpacePosition() );
4738 // keep inverse elements
4739 if ( !theCopy && !theTargetMesh && needReverse ) {
4740 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4741 while ( invElemIt->more() ) {
4742 const SMDS_MeshElement* iel = invElemIt->next();
4743 inverseElemSet.insert( iel );
4749 // either create new elements or reverse mirrored ones
4750 if ( !theCopy && !needReverse && !theTargetMesh )
4753 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4754 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4755 theElems.insert( *invElemIt );
4757 // replicate or reverse elements
4760 REV_TETRA = 0, // = nbNodes - 4
4761 REV_PYRAMID = 1, // = nbNodes - 4
4762 REV_PENTA = 2, // = nbNodes - 4
4764 REV_HEXA = 4, // = nbNodes - 4
4768 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4769 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4770 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4771 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4772 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4773 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4776 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4778 const SMDS_MeshElement* elem = *itElem;
4779 if ( !elem || elem->GetType() == SMDSAbs_Node )
4782 int nbNodes = elem->NbNodes();
4783 int elemType = elem->GetType();
4785 if (elem->IsPoly()) {
4786 // Polygon or Polyhedral Volume
4787 switch ( elemType ) {
4790 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4792 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4793 while (itN->more()) {
4794 const SMDS_MeshNode* node =
4795 static_cast<const SMDS_MeshNode*>(itN->next());
4796 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4797 if (nodeMapIt == nodeMap.end())
4798 break; // not all nodes transformed
4800 // reverse mirrored faces and volumes
4801 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4803 poly_nodes[iNode] = (*nodeMapIt).second;
4807 if ( iNode != nbNodes )
4808 continue; // not all nodes transformed
4810 if ( theTargetMesh ) {
4811 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4812 srcElems.Append( elem );
4814 else if ( theCopy ) {
4815 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4816 srcElems.Append( elem );
4819 aMesh->ChangePolygonNodes(elem, poly_nodes);
4823 case SMDSAbs_Volume:
4825 // ATTENTION: Reversing is not yet done!!!
4826 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4827 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4829 MESSAGE("Warning: bad volumic element");
4833 vector<const SMDS_MeshNode*> poly_nodes;
4834 vector<int> quantities;
4836 bool allTransformed = true;
4837 int nbFaces = aPolyedre->NbFaces();
4838 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4839 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4840 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4841 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4842 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4843 if (nodeMapIt == nodeMap.end()) {
4844 allTransformed = false; // not all nodes transformed
4846 poly_nodes.push_back((*nodeMapIt).second);
4849 quantities.push_back(nbFaceNodes);
4851 if ( !allTransformed )
4852 continue; // not all nodes transformed
4854 if ( theTargetMesh ) {
4855 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4856 srcElems.Append( elem );
4858 else if ( theCopy ) {
4859 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4860 srcElems.Append( elem );
4863 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4873 int* i = index[ FORWARD ];
4874 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4875 if ( elemType == SMDSAbs_Face )
4876 i = index[ REV_FACE ];
4878 i = index[ nbNodes - 4 ];
4880 if(elem->IsQuadratic()) {
4881 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4884 if(nbNodes==3) { // quadratic edge
4885 static int anIds[] = {1,0,2};
4888 else if(nbNodes==6) { // quadratic triangle
4889 static int anIds[] = {0,2,1,5,4,3};
4892 else if(nbNodes==8) { // quadratic quadrangle
4893 static int anIds[] = {0,3,2,1,7,6,5,4};
4896 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4897 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4900 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4901 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4904 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4905 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4908 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4909 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4915 // find transformed nodes
4916 vector<const SMDS_MeshNode*> nodes(nbNodes);
4918 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4919 while ( itN->more() ) {
4920 const SMDS_MeshNode* node =
4921 static_cast<const SMDS_MeshNode*>( itN->next() );
4922 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4923 if ( nodeMapIt == nodeMap.end() )
4924 break; // not all nodes transformed
4925 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4927 if ( iNode != nbNodes )
4928 continue; // not all nodes transformed
4930 if ( theTargetMesh ) {
4931 if ( SMDS_MeshElement* copy =
4932 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4933 myLastCreatedElems.Append( copy );
4934 srcElems.Append( elem );
4937 else if ( theCopy ) {
4938 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4939 myLastCreatedElems.Append( copy );
4940 srcElems.Append( elem );
4944 // reverse element as it was reversed by transformation
4946 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4950 PGroupIDs newGroupIDs;
4952 if ( theMakeGroups && theCopy ||
4953 theMakeGroups && theTargetMesh )
4954 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4959 //=======================================================================
4961 * \brief Create groups of elements made during transformation
4962 * \param nodeGens - nodes making corresponding myLastCreatedNodes
4963 * \param elemGens - elements making corresponding myLastCreatedElems
4964 * \param postfix - to append to names of new groups
4966 //=======================================================================
4968 SMESH_MeshEditor::PGroupIDs
4969 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4970 const SMESH_SequenceOfElemPtr& elemGens,
4971 const std::string& postfix,
4972 SMESH_Mesh* targetMesh)
4974 PGroupIDs newGroupIDs( new list<int> );
4975 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4977 // Sort existing groups by types and collect their names
4979 // to store an old group and a generated new one
4980 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4981 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4983 set< string > groupNames;
4985 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4986 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4987 while ( groupIt->more() ) {
4988 SMESH_Group * group = groupIt->next();
4989 if ( !group ) continue;
4990 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4991 if ( !groupDS || groupDS->IsEmpty() ) continue;
4992 groupNames.insert( group->GetName() );
4993 groupDS->SetStoreName( group->GetName() );
4994 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
4999 // loop on nodes and elements
5000 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5002 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5003 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5004 if ( gens.Length() != elems.Length() )
5005 throw SALOME_Exception(LOCALIZED("invalid args"));
5007 // loop on created elements
5008 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5010 const SMDS_MeshElement* sourceElem = gens( iElem );
5011 if ( !sourceElem ) {
5012 MESSAGE("generateGroups(): NULL source element");
5015 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5016 if ( groupsOldNew.empty() ) {
5017 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5018 ++iElem; // skip all elements made by sourceElem
5021 // collect all elements made by sourceElem
5022 list< const SMDS_MeshElement* > resultElems;
5023 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5024 if ( resElem != sourceElem )
5025 resultElems.push_back( resElem );
5026 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5027 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5028 if ( resElem != sourceElem )
5029 resultElems.push_back( resElem );
5030 // do not generate element groups from node ones
5031 if ( sourceElem->GetType() == SMDSAbs_Node &&
5032 elems( iElem )->GetType() != SMDSAbs_Node )
5035 // add resultElems to groups made by ones the sourceElem belongs to
5036 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5037 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5039 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5040 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5042 SMDS_MeshGroup* & newGroup = gOldNew->second;
5043 if ( !newGroup )// create a new group
5046 string name = oldGroup->GetStoreName();
5047 if ( !targetMesh ) {
5051 while ( !groupNames.insert( name ).second ) // name exists
5057 TCollection_AsciiString nbStr(nb+1);
5058 name.resize( name.rfind('_')+1 );
5059 name += nbStr.ToCString();
5066 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5068 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5069 newGroup = & groupDS->SMDSGroup();
5070 newGroupIDs->push_back( id );
5073 // fill in a new group
5074 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5075 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5076 newGroup->Add( *resElemIt );
5079 } // loop on created elements
5080 }// loop on nodes and elements
5085 //================================================================================
5087 * \brief Return list of group of nodes close to each other within theTolerance
5088 * Search among theNodes or in the whole mesh if theNodes is empty using
5089 * an Octree algorithm
5091 //================================================================================
5093 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5094 const double theTolerance,
5095 TListOfListOfNodes & theGroupsOfNodes)
5097 myLastCreatedElems.Clear();
5098 myLastCreatedNodes.Clear();
5100 set<const SMDS_MeshNode*> nodes;
5101 if ( theNodes.empty() )
5102 { // get all nodes in the mesh
5103 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5104 while ( nIt->more() )
5105 nodes.insert( nodes.end(),nIt->next());
5110 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5114 //=======================================================================
5116 * \brief Implementation of search for the node closest to point
5118 //=======================================================================
5120 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5122 //---------------------------------------------------------------------
5124 * \brief Constructor
5126 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5128 myMesh = ( SMESHDS_Mesh* ) theMesh;
5130 set<const SMDS_MeshNode*> nodes;
5132 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5133 while ( nIt->more() )
5134 nodes.insert( nodes.end(), nIt->next() );
5136 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5138 // get max size of a leaf box
5139 SMESH_OctreeNode* tree = myOctreeNode;
5140 while ( !tree->isLeaf() )
5142 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5146 myHalfLeafSize = tree->maxSize() / 2.;
5149 //---------------------------------------------------------------------
5151 * \brief Move node and update myOctreeNode accordingly
5153 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5155 myOctreeNode->UpdateByMoveNode( node, toPnt );
5156 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5159 //---------------------------------------------------------------------
5161 * \brief Do it's job
5163 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5165 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5166 map<double, const SMDS_MeshNode*> dist2Nodes;
5167 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5168 if ( !dist2Nodes.empty() )
5169 return dist2Nodes.begin()->second;
5170 list<const SMDS_MeshNode*> nodes;
5171 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5173 double minSqDist = DBL_MAX;
5174 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5176 // sort leafs by their distance from thePnt
5177 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5178 TDistTreeMap treeMap;
5179 list< SMESH_OctreeNode* > treeList;
5180 list< SMESH_OctreeNode* >::iterator trIt;
5181 treeList.push_back( myOctreeNode );
5183 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5184 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5186 SMESH_OctreeNode* tree = *trIt;
5187 if ( !tree->isLeaf() ) // put children to the queue
5189 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5190 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5191 while ( cIt->more() )
5192 treeList.push_back( cIt->next() );
5194 else if ( tree->NbNodes() ) // put a tree to the treeMap
5196 const Bnd_B3d& box = tree->getBox();
5197 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5198 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5199 if ( !it_in.second ) // not unique distance to box center
5200 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5203 // find distance after which there is no sense to check tree's
5204 double sqLimit = DBL_MAX;
5205 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5206 if ( treeMap.size() > 5 ) {
5207 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5208 const Bnd_B3d& box = closestTree->getBox();
5209 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5210 sqLimit = limit * limit;
5212 // get all nodes from trees
5213 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5214 if ( sqDist_tree->first > sqLimit )
5216 SMESH_OctreeNode* tree = sqDist_tree->second;
5217 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5220 // find closest among nodes
5221 minSqDist = DBL_MAX;
5222 const SMDS_MeshNode* closestNode = 0;
5223 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5224 for ( ; nIt != nodes.end(); ++nIt ) {
5225 double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
5226 if ( minSqDist > sqDist ) {
5234 //---------------------------------------------------------------------
5238 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5240 //---------------------------------------------------------------------
5242 * \brief Return the node tree
5244 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5247 SMESH_OctreeNode* myOctreeNode;
5248 SMESHDS_Mesh* myMesh;
5249 double myHalfLeafSize; // max size of a leaf box
5252 //=======================================================================
5254 * \brief Return SMESH_NodeSearcher
5256 //=======================================================================
5258 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5260 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5263 // ========================================================================
5264 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5266 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5267 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5268 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5270 //=======================================================================
5272 * \brief Octal tree of bounding boxes of elements
5274 //=======================================================================
5276 class ElementBndBoxTree : public SMESH_Octree
5280 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5281 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5282 ~ElementBndBoxTree();
5285 ElementBndBoxTree() {}
5286 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5287 void buildChildrenData();
5288 Bnd_B3d* buildRootBox();
5290 //!< Bounding box of element
5291 struct ElementBox : public Bnd_B3d
5293 const SMDS_MeshElement* _element;
5294 int _refCount; // an ElementBox can be included in several tree branches
5295 ElementBox(const SMDS_MeshElement* elem);
5297 vector< ElementBox* > _elements;
5300 //================================================================================
5302 * \brief ElementBndBoxTree creation
5304 //================================================================================
5306 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5307 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5309 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5310 _elements.reserve( nbElems );
5312 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5313 while ( elemIt->more() )
5314 _elements.push_back( new ElementBox( elemIt->next() ));
5316 if ( _elements.size() > MaxNbElemsInLeaf )
5322 //================================================================================
5326 //================================================================================
5328 ElementBndBoxTree::~ElementBndBoxTree()
5330 for ( int i = 0; i < _elements.size(); ++i )
5331 if ( --_elements[i]->_refCount <= 0 )
5332 delete _elements[i];
5335 //================================================================================
5337 * \brief Return the maximal box
5339 //================================================================================
5341 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5343 Bnd_B3d* box = new Bnd_B3d;
5344 for ( int i = 0; i < _elements.size(); ++i )
5345 box->Add( *_elements[i] );
5349 //================================================================================
5351 * \brief Redistrubute element boxes among children
5353 //================================================================================
5355 void ElementBndBoxTree::buildChildrenData()
5357 for ( int i = 0; i < _elements.size(); ++i )
5359 for (int j = 0; j < 8; j++)
5361 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5363 _elements[i]->_refCount++;
5364 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5367 _elements[i]->_refCount--;
5371 for (int j = 0; j < 8; j++)
5373 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5374 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5375 child->myIsLeaf = true;
5377 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5378 child->_elements.resize( child->_elements.size() ); // compact
5382 //================================================================================
5384 * \brief Return elements which can include the point
5386 //================================================================================
5388 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5389 TIDSortedElemSet& foundElems)
5391 if ( level() && getBox().IsOut( point.XYZ() ))
5396 for ( int i = 0; i < _elements.size(); ++i )
5397 if ( !_elements[i]->IsOut( point.XYZ() ))
5398 foundElems.insert( _elements[i]->_element );
5402 for (int i = 0; i < 8; i++)
5403 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5407 //================================================================================
5409 * \brief Construct the element box
5411 //================================================================================
5413 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5417 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5418 while ( nIt->more() )
5419 Add( TNodeXYZ( cast2Node( nIt->next() )));
5420 Enlarge( NodeRadius );
5425 //=======================================================================
5427 * \brief Implementation of search for the elements by point
5429 //=======================================================================
5431 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5433 SMESHDS_Mesh* _mesh;
5434 ElementBndBoxTree* _ebbTree;
5435 SMESH_NodeSearcherImpl* _nodeSearcher;
5436 SMDSAbs_ElementType _elementType;
5438 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh ): _mesh(&mesh),_ebbTree(0),_nodeSearcher(0) {}
5439 ~SMESH_ElementSearcherImpl()
5441 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
5442 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5446 * \brief Return elements of given type where the given point is IN or ON.
5448 * 'ALL' type means elements of any type excluding nodes and 0D elements
5450 void FindElementsByPoint(const gp_Pnt& point,
5451 SMDSAbs_ElementType type,
5452 vector< const SMDS_MeshElement* >& foundElements)
5454 foundElements.clear();
5456 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5458 // -----------------
5460 // -----------------
5461 double tolerance = 0;
5462 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5464 double boxSize = _nodeSearcher->getTree()->maxSize();
5465 tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
5467 else if ( _ebbTree && meshInfo.NbElements() > 0 )
5469 double boxSize = _ebbTree->maxSize();
5470 tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
5472 if ( tolerance == 0 )
5474 // define tolerance by size of a most complex element
5475 int complexType = SMDSAbs_Volume;
5476 while ( complexType > SMDSAbs_All &&
5477 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
5479 if ( complexType == SMDSAbs_All ) return; // empty mesh
5482 if ( complexType == int( SMDSAbs_Node ))
5484 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
5486 if ( meshInfo.NbNodes() > 2 )
5487 elemSize = TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
5491 const SMDS_MeshElement* elem =
5492 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
5493 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
5494 TNodeXYZ n1( cast2Node( nodeIt->next() ));
5495 while ( nodeIt->more() )
5497 double dist = n1.Distance( cast2Node( nodeIt->next() ));
5498 elemSize = max( dist, elemSize );
5501 tolerance = 1e-6 * elemSize;
5504 // =================================================================================
5505 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
5507 if ( !_nodeSearcher )
5508 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
5510 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
5511 if ( !closeNode ) return;
5513 if ( point.Distance( TNodeXYZ( closeNode )) > tolerance )
5514 return; // to far from any node
5516 if ( type == SMDSAbs_Node )
5518 foundElements.push_back( closeNode );
5522 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
5523 while ( elemIt->more() )
5524 foundElements.push_back( elemIt->next() );
5527 // =================================================================================
5528 else // elements more complex than 0D
5530 if ( !_ebbTree || _elementType != type )
5532 if ( _ebbTree ) delete _ebbTree;
5533 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
5535 TIDSortedElemSet suspectElems;
5536 _ebbTree->getElementsNearPoint( point, suspectElems );
5537 TIDSortedElemSet::iterator elem = suspectElems.begin();
5538 for ( ; elem != suspectElems.end(); ++elem )
5539 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
5540 foundElements.push_back( *elem );
5543 }; // struct SMESH_ElementSearcherImpl
5545 //=======================================================================
5547 * \brief Return SMESH_ElementSearcher
5549 //=======================================================================
5551 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
5553 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
5556 //=======================================================================
5558 * \brief Return true if the point is IN or ON of the element
5560 //=======================================================================
5562 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
5564 if ( element->GetType() == SMDSAbs_Volume)
5566 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
5569 // get ordered nodes
5571 vector< gp_XYZ > xyz;
5573 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
5574 if ( element->IsQuadratic() )
5575 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
5576 nodeIt = f->interlacedNodesElemIterator();
5577 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
5578 nodeIt = e->interlacedNodesElemIterator();
5580 while ( nodeIt->more() )
5581 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
5583 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
5587 gc = accumulate( xyz.begin(), xyz.end(), gc );
5588 gc /= element->NbNodes();
5590 // compute face normal using gc
5591 gp_Vec normal(0,0,0);
5592 xyz.push_back( xyz.front() );
5593 for ( int i = 0; i < element->NbNodes(); ++i )
5595 gp_Vec edge( xyz[i], xyz[i+1]);
5596 gp_Vec n2gc( xyz[i], gc );
5597 normal += edge ^ n2gc;
5599 double faceDoubleArea = normal.Magnitude();
5600 if ( faceDoubleArea <= numeric_limits<double>::min() )
5601 return true; // invalid face
5602 normal /= faceDoubleArea;
5604 // check if the point lays on face plane
5605 gp_Vec n2p( xyz[0], point );
5606 if ( fabs( n2p * normal ) > tol )
5607 return true; // not on face plane
5609 // check if point is out of face boundary
5611 for ( i = 0; !out && i < element->NbNodes(); ++i )
5613 gp_Vec edge( xyz[i], xyz[i+1]);
5614 gp_Vec n2p ( xyz[i], point );
5615 gp_Vec cross = edge ^ n2p;
5616 out = ( cross * normal < -tol );
5618 if ( out && element->IsPoly() )
5620 // define point position by the closest edge
5621 double minDist = numeric_limits<double>::max();
5623 for ( i = 0; i < element->NbNodes(); ++i )
5625 gp_Vec edge( xyz[i], xyz[i+1]);
5626 gp_Vec n1p ( xyz[i], point);
5627 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
5628 if ( dist < minDist )
5631 gp_Vec edge( xyz[iMinDist], xyz[iMinDist+1]);
5632 gp_Vec n2p ( xyz[iMinDist], point );
5633 gp_Vec cross = edge ^ n2p;
5634 out = ( cross * normal < -tol );
5638 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
5640 for ( int i = 1; i < element->NbNodes(); ++i )
5642 gp_Vec edge( xyz[i-1], xyz[i]);
5643 gp_Vec n1p ( xyz[i-1], point);
5644 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
5647 gp_Vec n2p( xyz[i], point );
5648 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
5653 // Node or 0D element -------------------------------------------------------------------------
5655 gp_Vec n2p ( xyz[0], point );
5656 return n2p.Magnitude() <= tol;
5661 //=======================================================================
5662 //function : SimplifyFace
5664 //=======================================================================
5665 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5666 vector<const SMDS_MeshNode *>& poly_nodes,
5667 vector<int>& quantities) const
5669 int nbNodes = faceNodes.size();
5674 set<const SMDS_MeshNode*> nodeSet;
5676 // get simple seq of nodes
5677 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5678 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5679 int iSimple = 0, nbUnique = 0;
5681 simpleNodes[iSimple++] = faceNodes[0];
5683 for (int iCur = 1; iCur < nbNodes; iCur++) {
5684 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5685 simpleNodes[iSimple++] = faceNodes[iCur];
5686 if (nodeSet.insert( faceNodes[iCur] ).second)
5690 int nbSimple = iSimple;
5691 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5701 bool foundLoop = (nbSimple > nbUnique);
5704 set<const SMDS_MeshNode*> loopSet;
5705 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5706 const SMDS_MeshNode* n = simpleNodes[iSimple];
5707 if (!loopSet.insert( n ).second) {
5711 int iC = 0, curLast = iSimple;
5712 for (; iC < curLast; iC++) {
5713 if (simpleNodes[iC] == n) break;
5715 int loopLen = curLast - iC;
5717 // create sub-element
5719 quantities.push_back(loopLen);
5720 for (; iC < curLast; iC++) {
5721 poly_nodes.push_back(simpleNodes[iC]);
5724 // shift the rest nodes (place from the first loop position)
5725 for (iC = curLast + 1; iC < nbSimple; iC++) {
5726 simpleNodes[iC - loopLen] = simpleNodes[iC];
5728 nbSimple -= loopLen;
5731 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5732 } // while (foundLoop)
5736 quantities.push_back(iSimple);
5737 for (int i = 0; i < iSimple; i++)
5738 poly_nodes.push_back(simpleNodes[i]);
5744 //=======================================================================
5745 //function : MergeNodes
5746 //purpose : In each group, the cdr of nodes are substituted by the first one
5748 //=======================================================================
5750 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5752 myLastCreatedElems.Clear();
5753 myLastCreatedNodes.Clear();
5755 SMESHDS_Mesh* aMesh = GetMeshDS();
5757 TNodeNodeMap nodeNodeMap; // node to replace - new node
5758 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5759 list< int > rmElemIds, rmNodeIds;
5761 // Fill nodeNodeMap and elems
5763 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5764 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5765 list<const SMDS_MeshNode*>& nodes = *grIt;
5766 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5767 const SMDS_MeshNode* nToKeep = *nIt;
5768 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5769 const SMDS_MeshNode* nToRemove = *nIt;
5770 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5771 if ( nToRemove != nToKeep ) {
5772 rmNodeIds.push_back( nToRemove->GetID() );
5773 AddToSameGroups( nToKeep, nToRemove, aMesh );
5776 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5777 while ( invElemIt->more() ) {
5778 const SMDS_MeshElement* elem = invElemIt->next();
5783 // Change element nodes or remove an element
5785 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5786 for ( ; eIt != elems.end(); eIt++ ) {
5787 const SMDS_MeshElement* elem = *eIt;
5788 int nbNodes = elem->NbNodes();
5789 int aShapeId = FindShape( elem );
5791 set<const SMDS_MeshNode*> nodeSet;
5792 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5793 int iUnique = 0, iCur = 0, nbRepl = 0;
5794 vector<int> iRepl( nbNodes );
5796 // get new seq of nodes
5797 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5798 while ( itN->more() ) {
5799 const SMDS_MeshNode* n =
5800 static_cast<const SMDS_MeshNode*>( itN->next() );
5802 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5803 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5805 // BUG 0020185: begin
5807 bool stopRecur = false;
5808 set<const SMDS_MeshNode*> nodesRecur;
5809 nodesRecur.insert(n);
5810 while (!stopRecur) {
5811 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5812 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5813 n = (*nnIt_i).second;
5814 if (!nodesRecur.insert(n).second) {
5815 // error: recursive dependancy
5824 iRepl[ nbRepl++ ] = iCur;
5826 curNodes[ iCur ] = n;
5827 bool isUnique = nodeSet.insert( n ).second;
5829 uniqueNodes[ iUnique++ ] = n;
5833 // Analyse element topology after replacement
5836 int nbUniqueNodes = nodeSet.size();
5837 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5838 // Polygons and Polyhedral volumes
5839 if (elem->IsPoly()) {
5841 if (elem->GetType() == SMDSAbs_Face) {
5843 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5845 for (; inode < nbNodes; inode++) {
5846 face_nodes[inode] = curNodes[inode];
5849 vector<const SMDS_MeshNode *> polygons_nodes;
5850 vector<int> quantities;
5851 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5855 for (int iface = 0; iface < nbNew - 1; iface++) {
5856 int nbNodes = quantities[iface];
5857 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5858 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5859 poly_nodes[ii] = polygons_nodes[inode];
5861 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5862 myLastCreatedElems.Append(newElem);
5864 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5866 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5869 rmElemIds.push_back(elem->GetID());
5873 else if (elem->GetType() == SMDSAbs_Volume) {
5874 // Polyhedral volume
5875 if (nbUniqueNodes < 4) {
5876 rmElemIds.push_back(elem->GetID());
5879 // each face has to be analized in order to check volume validity
5880 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5881 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5883 int nbFaces = aPolyedre->NbFaces();
5885 vector<const SMDS_MeshNode *> poly_nodes;
5886 vector<int> quantities;
5888 for (int iface = 1; iface <= nbFaces; iface++) {
5889 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5890 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5892 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5893 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5894 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5895 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5896 faceNode = (*nnIt).second;
5898 faceNodes[inode - 1] = faceNode;
5901 SimplifyFace(faceNodes, poly_nodes, quantities);
5904 if (quantities.size() > 3) {
5905 // to be done: remove coincident faces
5908 if (quantities.size() > 3)
5909 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5911 rmElemIds.push_back(elem->GetID());
5915 rmElemIds.push_back(elem->GetID());
5926 switch ( nbNodes ) {
5927 case 2: ///////////////////////////////////// EDGE
5928 isOk = false; break;
5929 case 3: ///////////////////////////////////// TRIANGLE
5930 isOk = false; break;
5932 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5934 else { //////////////////////////////////// QUADRANGLE
5935 if ( nbUniqueNodes < 3 )
5937 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5938 isOk = false; // opposite nodes stick
5941 case 6: ///////////////////////////////////// PENTAHEDRON
5942 if ( nbUniqueNodes == 4 ) {
5943 // ---------------------------------> tetrahedron
5945 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5946 // all top nodes stick: reverse a bottom
5947 uniqueNodes[ 0 ] = curNodes [ 1 ];
5948 uniqueNodes[ 1 ] = curNodes [ 0 ];
5950 else if (nbRepl == 3 &&
5951 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5952 // all bottom nodes stick: set a top before
5953 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5954 uniqueNodes[ 0 ] = curNodes [ 3 ];
5955 uniqueNodes[ 1 ] = curNodes [ 4 ];
5956 uniqueNodes[ 2 ] = curNodes [ 5 ];
5958 else if (nbRepl == 4 &&
5959 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5960 // a lateral face turns into a line: reverse a bottom
5961 uniqueNodes[ 0 ] = curNodes [ 1 ];
5962 uniqueNodes[ 1 ] = curNodes [ 0 ];
5967 else if ( nbUniqueNodes == 5 ) {
5968 // PENTAHEDRON --------------------> 2 tetrahedrons
5969 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
5970 // a bottom node sticks with a linked top one
5972 SMDS_MeshElement* newElem =
5973 aMesh->AddVolume(curNodes[ 3 ],
5976 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
5977 myLastCreatedElems.Append(newElem);
5979 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5980 // 2. : reverse a bottom
5981 uniqueNodes[ 0 ] = curNodes [ 1 ];
5982 uniqueNodes[ 1 ] = curNodes [ 0 ];
5992 if(elem->IsQuadratic()) { // Quadratic quadrangle
6005 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6006 uniqueNodes[0] = curNodes[0];
6007 uniqueNodes[1] = curNodes[2];
6008 uniqueNodes[2] = curNodes[3];
6009 uniqueNodes[3] = curNodes[5];
6010 uniqueNodes[4] = curNodes[6];
6011 uniqueNodes[5] = curNodes[7];
6014 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6015 uniqueNodes[0] = curNodes[0];
6016 uniqueNodes[1] = curNodes[1];
6017 uniqueNodes[2] = curNodes[2];
6018 uniqueNodes[3] = curNodes[4];
6019 uniqueNodes[4] = curNodes[5];
6020 uniqueNodes[5] = curNodes[6];
6023 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6024 uniqueNodes[0] = curNodes[1];
6025 uniqueNodes[1] = curNodes[2];
6026 uniqueNodes[2] = curNodes[3];
6027 uniqueNodes[3] = curNodes[5];
6028 uniqueNodes[4] = curNodes[6];
6029 uniqueNodes[5] = curNodes[0];
6032 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6033 uniqueNodes[0] = curNodes[0];
6034 uniqueNodes[1] = curNodes[1];
6035 uniqueNodes[2] = curNodes[3];
6036 uniqueNodes[3] = curNodes[4];
6037 uniqueNodes[4] = curNodes[6];
6038 uniqueNodes[5] = curNodes[7];
6041 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6042 uniqueNodes[0] = curNodes[0];
6043 uniqueNodes[1] = curNodes[2];
6044 uniqueNodes[2] = curNodes[3];
6045 uniqueNodes[3] = curNodes[1];
6046 uniqueNodes[4] = curNodes[6];
6047 uniqueNodes[5] = curNodes[7];
6050 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6051 uniqueNodes[0] = curNodes[0];
6052 uniqueNodes[1] = curNodes[1];
6053 uniqueNodes[2] = curNodes[2];
6054 uniqueNodes[3] = curNodes[4];
6055 uniqueNodes[4] = curNodes[5];
6056 uniqueNodes[5] = curNodes[7];
6059 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6060 uniqueNodes[0] = curNodes[0];
6061 uniqueNodes[1] = curNodes[1];
6062 uniqueNodes[2] = curNodes[3];
6063 uniqueNodes[3] = curNodes[4];
6064 uniqueNodes[4] = curNodes[2];
6065 uniqueNodes[5] = curNodes[7];
6068 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6069 uniqueNodes[0] = curNodes[0];
6070 uniqueNodes[1] = curNodes[1];
6071 uniqueNodes[2] = curNodes[2];
6072 uniqueNodes[3] = curNodes[4];
6073 uniqueNodes[4] = curNodes[5];
6074 uniqueNodes[5] = curNodes[3];
6080 //////////////////////////////////// HEXAHEDRON
6082 SMDS_VolumeTool hexa (elem);
6083 hexa.SetExternalNormal();
6084 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6085 //////////////////////// ---> tetrahedron
6086 for ( int iFace = 0; iFace < 6; iFace++ ) {
6087 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6088 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6089 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6090 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6091 // one face turns into a point ...
6092 int iOppFace = hexa.GetOppFaceIndex( iFace );
6093 ind = hexa.GetFaceNodesIndices( iOppFace );
6095 iUnique = 2; // reverse a tetrahedron bottom
6096 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6097 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6099 else if ( iUnique >= 0 )
6100 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6102 if ( nbStick == 1 ) {
6103 // ... and the opposite one - into a triangle.
6105 ind = hexa.GetFaceNodesIndices( iFace );
6106 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6113 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6114 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6115 for ( int iFace = 0; iFace < 6; iFace++ ) {
6116 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6117 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6118 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6119 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6120 // one face turns into a point ...
6121 int iOppFace = hexa.GetOppFaceIndex( iFace );
6122 ind = hexa.GetFaceNodesIndices( iOppFace );
6124 iUnique = 2; // reverse a tetrahedron 1 bottom
6125 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6126 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6128 else if ( iUnique >= 0 )
6129 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6131 if ( nbStick == 0 ) {
6132 // ... and the opposite one is a quadrangle
6134 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6135 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6138 SMDS_MeshElement* newElem =
6139 aMesh->AddVolume(curNodes[ind[ 0 ]],
6142 curNodes[indTop[ 0 ]]);
6143 myLastCreatedElems.Append(newElem);
6145 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6152 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6153 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6154 // find indices of quad and tri faces
6155 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6156 for ( iFace = 0; iFace < 6; iFace++ ) {
6157 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6159 for ( iCur = 0; iCur < 4; iCur++ )
6160 nodeSet.insert( curNodes[ind[ iCur ]] );
6161 nbUniqueNodes = nodeSet.size();
6162 if ( nbUniqueNodes == 3 )
6163 iTriFace[ nbTri++ ] = iFace;
6164 else if ( nbUniqueNodes == 4 )
6165 iQuadFace[ nbQuad++ ] = iFace;
6167 if (nbQuad == 2 && nbTri == 4 &&
6168 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6169 // 2 opposite quadrangles stuck with a diagonal;
6170 // sample groups of merged indices: (0-4)(2-6)
6171 // --------------------------------------------> 2 tetrahedrons
6172 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6173 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6174 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6175 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6176 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6177 // stuck with 0-2 diagonal
6185 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6186 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6187 // stuck with 1-3 diagonal
6199 uniqueNodes[ 0 ] = curNodes [ i0 ];
6200 uniqueNodes[ 1 ] = curNodes [ i1d ];
6201 uniqueNodes[ 2 ] = curNodes [ i3d ];
6202 uniqueNodes[ 3 ] = curNodes [ i0t ];
6205 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6209 myLastCreatedElems.Append(newElem);
6211 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6214 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6215 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6216 // --------------------------------------------> prism
6217 // find 2 opposite triangles
6219 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6220 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6221 // find indices of kept and replaced nodes
6222 // and fill unique nodes of 2 opposite triangles
6223 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6224 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6225 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6226 // fill unique nodes
6229 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6230 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
6231 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6233 // iCur of a linked node of the opposite face (make normals co-directed):
6234 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6235 // check that correspondent corners of triangles are linked
6236 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6239 uniqueNodes[ iUnique ] = n;
6240 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6249 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6255 } // switch ( nbNodes )
6257 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6260 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
6261 // Change nodes of polyedre
6262 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6263 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6265 int nbFaces = aPolyedre->NbFaces();
6267 vector<const SMDS_MeshNode *> poly_nodes;
6268 vector<int> quantities (nbFaces);
6270 for (int iface = 1; iface <= nbFaces; iface++) {
6271 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6272 quantities[iface - 1] = nbFaceNodes;
6274 for (inode = 1; inode <= nbFaceNodes; inode++) {
6275 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6277 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6278 if (nnIt != nodeNodeMap.end()) { // curNode sticks
6279 curNode = (*nnIt).second;
6281 poly_nodes.push_back(curNode);
6284 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6288 // Change regular element or polygon
6289 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
6293 // Remove invalid regular element or invalid polygon
6294 rmElemIds.push_back( elem->GetID() );
6297 } // loop on elements
6299 // Remove equal nodes and bad elements
6301 Remove( rmNodeIds, true );
6302 Remove( rmElemIds, false );
6307 // ========================================================
6308 // class : SortableElement
6309 // purpose : allow sorting elements basing on their nodes
6310 // ========================================================
6311 class SortableElement : public set <const SMDS_MeshElement*>
6315 SortableElement( const SMDS_MeshElement* theElem )
6318 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6319 while ( nodeIt->more() )
6320 this->insert( nodeIt->next() );
6323 const SMDS_MeshElement* Get() const
6326 void Set(const SMDS_MeshElement* e) const
6331 mutable const SMDS_MeshElement* myElem;
6334 //=======================================================================
6335 //function : FindEqualElements
6336 //purpose : Return list of group of elements built on the same nodes.
6337 // Search among theElements or in the whole mesh if theElements is empty
6338 //=======================================================================
6339 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
6340 TListOfListOfElementsID & theGroupsOfElementsID)
6342 myLastCreatedElems.Clear();
6343 myLastCreatedNodes.Clear();
6345 typedef set<const SMDS_MeshElement*> TElemsSet;
6346 typedef map< SortableElement, int > TMapOfNodeSet;
6347 typedef list<int> TGroupOfElems;
6350 if ( theElements.empty() )
6351 { // get all elements in the mesh
6352 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
6353 while ( eIt->more() )
6354 elems.insert( elems.end(), eIt->next());
6357 elems = theElements;
6359 vector< TGroupOfElems > arrayOfGroups;
6360 TGroupOfElems groupOfElems;
6361 TMapOfNodeSet mapOfNodeSet;
6363 TElemsSet::iterator elemIt = elems.begin();
6364 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
6365 const SMDS_MeshElement* curElem = *elemIt;
6366 SortableElement SE(curElem);
6369 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
6370 if( !(pp.second) ) {
6371 TMapOfNodeSet::iterator& itSE = pp.first;
6372 ind = (*itSE).second;
6373 arrayOfGroups[ind].push_back(curElem->GetID());
6376 groupOfElems.clear();
6377 groupOfElems.push_back(curElem->GetID());
6378 arrayOfGroups.push_back(groupOfElems);
6383 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
6384 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
6385 groupOfElems = *groupIt;
6386 if ( groupOfElems.size() > 1 ) {
6387 groupOfElems.sort();
6388 theGroupsOfElementsID.push_back(groupOfElems);
6393 //=======================================================================
6394 //function : MergeElements
6395 //purpose : In each given group, substitute all elements by the first one.
6396 //=======================================================================
6398 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
6400 myLastCreatedElems.Clear();
6401 myLastCreatedNodes.Clear();
6403 typedef list<int> TListOfIDs;
6404 TListOfIDs rmElemIds; // IDs of elems to remove
6406 SMESHDS_Mesh* aMesh = GetMeshDS();
6408 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
6409 while ( groupsIt != theGroupsOfElementsID.end() ) {
6410 TListOfIDs& aGroupOfElemID = *groupsIt;
6411 aGroupOfElemID.sort();
6412 int elemIDToKeep = aGroupOfElemID.front();
6413 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
6414 aGroupOfElemID.pop_front();
6415 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
6416 while ( idIt != aGroupOfElemID.end() ) {
6417 int elemIDToRemove = *idIt;
6418 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
6419 // add the kept element in groups of removed one (PAL15188)
6420 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
6421 rmElemIds.push_back( elemIDToRemove );
6427 Remove( rmElemIds, false );
6430 //=======================================================================
6431 //function : MergeEqualElements
6432 //purpose : Remove all but one of elements built on the same nodes.
6433 //=======================================================================
6435 void SMESH_MeshEditor::MergeEqualElements()
6437 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
6438 to merge equal elements in the whole mesh */
6439 TListOfListOfElementsID aGroupsOfElementsID;
6440 FindEqualElements(aMeshElements, aGroupsOfElementsID);
6441 MergeElements(aGroupsOfElementsID);
6444 //=======================================================================
6445 //function : FindFaceInSet
6446 //purpose : Return a face having linked nodes n1 and n2 and which is
6447 // - not in avoidSet,
6448 // - in elemSet provided that !elemSet.empty()
6449 //=======================================================================
6451 const SMDS_MeshElement*
6452 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
6453 const SMDS_MeshNode* n2,
6454 const TIDSortedElemSet& elemSet,
6455 const TIDSortedElemSet& avoidSet)
6458 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
6459 while ( invElemIt->more() ) { // loop on inverse elements of n1
6460 const SMDS_MeshElement* elem = invElemIt->next();
6461 if (avoidSet.find( elem ) != avoidSet.end() )
6463 if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
6465 // get face nodes and find index of n1
6466 int i1, nbN = elem->NbNodes(), iNode = 0;
6467 //const SMDS_MeshNode* faceNodes[ nbN ], *n;
6468 vector<const SMDS_MeshNode*> faceNodes( nbN );
6469 const SMDS_MeshNode* n;
6470 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6471 while ( nIt->more() ) {
6472 faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6473 if ( faceNodes[ iNode++ ] == n1 )
6476 // find a n2 linked to n1
6477 if(!elem->IsQuadratic()) {
6478 for ( iNode = 0; iNode < 2; iNode++ ) {
6479 if ( iNode ) // node before n1
6480 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6481 else // node after n1
6482 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6487 else { // analysis for quadratic elements
6488 bool IsFind = false;
6489 // check using only corner nodes
6490 for ( iNode = 0; iNode < 2; iNode++ ) {
6491 if ( iNode ) // node before n1
6492 n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
6493 else // node after n1
6494 n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
6502 // check using all nodes
6503 const SMDS_QuadraticFaceOfNodes* F =
6504 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6505 // use special nodes iterator
6507 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6508 while ( anIter->more() ) {
6509 faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
6510 if ( faceNodes[ iNode++ ] == n1 )
6513 for ( iNode = 0; iNode < 2; iNode++ ) {
6514 if ( iNode ) // node before n1
6515 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6516 else // node after n1
6517 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6523 } // end analysis for quadratic elements
6528 //=======================================================================
6529 //function : findAdjacentFace
6531 //=======================================================================
6533 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6534 const SMDS_MeshNode* n2,
6535 const SMDS_MeshElement* elem)
6537 TIDSortedElemSet elemSet, avoidSet;
6539 avoidSet.insert ( elem );
6540 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6543 //=======================================================================
6544 //function : FindFreeBorder
6546 //=======================================================================
6548 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6550 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
6551 const SMDS_MeshNode* theSecondNode,
6552 const SMDS_MeshNode* theLastNode,
6553 list< const SMDS_MeshNode* > & theNodes,
6554 list< const SMDS_MeshElement* >& theFaces)
6556 if ( !theFirstNode || !theSecondNode )
6558 // find border face between theFirstNode and theSecondNode
6559 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6563 theFaces.push_back( curElem );
6564 theNodes.push_back( theFirstNode );
6565 theNodes.push_back( theSecondNode );
6567 //vector<const SMDS_MeshNode*> nodes;
6568 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6569 TIDSortedElemSet foundElems;
6570 bool needTheLast = ( theLastNode != 0 );
6572 while ( nStart != theLastNode ) {
6573 if ( nStart == theFirstNode )
6574 return !needTheLast;
6576 // find all free border faces sharing form nStart
6578 list< const SMDS_MeshElement* > curElemList;
6579 list< const SMDS_MeshNode* > nStartList;
6580 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6581 while ( invElemIt->more() ) {
6582 const SMDS_MeshElement* e = invElemIt->next();
6583 if ( e == curElem || foundElems.insert( e ).second ) {
6585 int iNode = 0, nbNodes = e->NbNodes();
6586 //const SMDS_MeshNode* nodes[nbNodes+1];
6587 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6589 if(e->IsQuadratic()) {
6590 const SMDS_QuadraticFaceOfNodes* F =
6591 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6592 // use special nodes iterator
6593 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6594 while( anIter->more() ) {
6595 nodes[ iNode++ ] = anIter->next();
6599 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6600 while ( nIt->more() )
6601 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6603 nodes[ iNode ] = nodes[ 0 ];
6605 for ( iNode = 0; iNode < nbNodes; iNode++ )
6606 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6607 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6608 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6610 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6611 curElemList.push_back( e );
6615 // analyse the found
6617 int nbNewBorders = curElemList.size();
6618 if ( nbNewBorders == 0 ) {
6619 // no free border furthermore
6620 return !needTheLast;
6622 else if ( nbNewBorders == 1 ) {
6623 // one more element found
6625 nStart = nStartList.front();
6626 curElem = curElemList.front();
6627 theFaces.push_back( curElem );
6628 theNodes.push_back( nStart );
6631 // several continuations found
6632 list< const SMDS_MeshElement* >::iterator curElemIt;
6633 list< const SMDS_MeshNode* >::iterator nStartIt;
6634 // check if one of them reached the last node
6635 if ( needTheLast ) {
6636 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6637 curElemIt!= curElemList.end();
6638 curElemIt++, nStartIt++ )
6639 if ( *nStartIt == theLastNode ) {
6640 theFaces.push_back( *curElemIt );
6641 theNodes.push_back( *nStartIt );
6645 // find the best free border by the continuations
6646 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6647 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6648 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6649 curElemIt!= curElemList.end();
6650 curElemIt++, nStartIt++ )
6652 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6653 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6654 // find one more free border
6655 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6659 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6660 // choice: clear a worse one
6661 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6662 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6663 contNodes[ iWorse ].clear();
6664 contFaces[ iWorse ].clear();
6667 if ( contNodes[0].empty() && contNodes[1].empty() )
6670 // append the best free border
6671 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6672 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6673 theNodes.pop_back(); // remove nIgnore
6674 theNodes.pop_back(); // remove nStart
6675 theFaces.pop_back(); // remove curElem
6676 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6677 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6678 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6679 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6682 } // several continuations found
6683 } // while ( nStart != theLastNode )
6688 //=======================================================================
6689 //function : CheckFreeBorderNodes
6690 //purpose : Return true if the tree nodes are on a free border
6691 //=======================================================================
6693 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6694 const SMDS_MeshNode* theNode2,
6695 const SMDS_MeshNode* theNode3)
6697 list< const SMDS_MeshNode* > nodes;
6698 list< const SMDS_MeshElement* > faces;
6699 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6702 //=======================================================================
6703 //function : SewFreeBorder
6705 //=======================================================================
6707 SMESH_MeshEditor::Sew_Error
6708 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6709 const SMDS_MeshNode* theBordSecondNode,
6710 const SMDS_MeshNode* theBordLastNode,
6711 const SMDS_MeshNode* theSideFirstNode,
6712 const SMDS_MeshNode* theSideSecondNode,
6713 const SMDS_MeshNode* theSideThirdNode,
6714 const bool theSideIsFreeBorder,
6715 const bool toCreatePolygons,
6716 const bool toCreatePolyedrs)
6718 myLastCreatedElems.Clear();
6719 myLastCreatedNodes.Clear();
6721 MESSAGE("::SewFreeBorder()");
6722 Sew_Error aResult = SEW_OK;
6724 // ====================================
6725 // find side nodes and elements
6726 // ====================================
6728 list< const SMDS_MeshNode* > nSide[ 2 ];
6729 list< const SMDS_MeshElement* > eSide[ 2 ];
6730 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6731 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6735 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6736 nSide[0], eSide[0])) {
6737 MESSAGE(" Free Border 1 not found " );
6738 aResult = SEW_BORDER1_NOT_FOUND;
6740 if (theSideIsFreeBorder) {
6743 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6744 nSide[1], eSide[1])) {
6745 MESSAGE(" Free Border 2 not found " );
6746 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6749 if ( aResult != SEW_OK )
6752 if (!theSideIsFreeBorder) {
6756 // -------------------------------------------------------------------------
6758 // 1. If nodes to merge are not coincident, move nodes of the free border
6759 // from the coord sys defined by the direction from the first to last
6760 // nodes of the border to the correspondent sys of the side 2
6761 // 2. On the side 2, find the links most co-directed with the correspondent
6762 // links of the free border
6763 // -------------------------------------------------------------------------
6765 // 1. Since sewing may brake if there are volumes to split on the side 2,
6766 // we wont move nodes but just compute new coordinates for them
6767 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6768 TNodeXYZMap nBordXYZ;
6769 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6770 list< const SMDS_MeshNode* >::iterator nBordIt;
6772 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6773 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6774 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6775 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6776 double tol2 = 1.e-8;
6777 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6778 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6779 // Need node movement.
6781 // find X and Z axes to create trsf
6782 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6784 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6786 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6789 gp_Ax3 toBordAx( Pb1, Zb, X );
6790 gp_Ax3 fromSideAx( Ps1, Zs, X );
6791 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6793 gp_Trsf toBordSys, fromSide2Sys;
6794 toBordSys.SetTransformation( toBordAx );
6795 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6796 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6799 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6800 const SMDS_MeshNode* n = *nBordIt;
6801 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6802 toBordSys.Transforms( xyz );
6803 fromSide2Sys.Transforms( xyz );
6804 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6808 // just insert nodes XYZ in the nBordXYZ map
6809 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6810 const SMDS_MeshNode* n = *nBordIt;
6811 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6815 // 2. On the side 2, find the links most co-directed with the correspondent
6816 // links of the free border
6818 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6819 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6820 sideNodes.push_back( theSideFirstNode );
6822 bool hasVolumes = false;
6823 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6824 set<long> foundSideLinkIDs, checkedLinkIDs;
6825 SMDS_VolumeTool volume;
6826 //const SMDS_MeshNode* faceNodes[ 4 ];
6828 const SMDS_MeshNode* sideNode;
6829 const SMDS_MeshElement* sideElem;
6830 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6831 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6832 nBordIt = bordNodes.begin();
6834 // border node position and border link direction to compare with
6835 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6836 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6837 // choose next side node by link direction or by closeness to
6838 // the current border node:
6839 bool searchByDir = ( *nBordIt != theBordLastNode );
6841 // find the next node on the Side 2
6843 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6845 checkedLinkIDs.clear();
6846 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6848 // loop on inverse elements of current node (prevSideNode) on the Side 2
6849 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6850 while ( invElemIt->more() )
6852 const SMDS_MeshElement* elem = invElemIt->next();
6853 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6854 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6855 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6856 bool isVolume = volume.Set( elem );
6857 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6858 if ( isVolume ) // --volume
6860 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6861 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6862 if(elem->IsQuadratic()) {
6863 const SMDS_QuadraticFaceOfNodes* F =
6864 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6865 // use special nodes iterator
6866 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6867 while( anIter->more() ) {
6868 nodes[ iNode ] = anIter->next();
6869 if ( nodes[ iNode++ ] == prevSideNode )
6870 iPrevNode = iNode - 1;
6874 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6875 while ( nIt->more() ) {
6876 nodes[ iNode ] = cast2Node( nIt->next() );
6877 if ( nodes[ iNode++ ] == prevSideNode )
6878 iPrevNode = iNode - 1;
6881 // there are 2 links to check
6886 // loop on links, to be precise, on the second node of links
6887 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6888 const SMDS_MeshNode* n = nodes[ iNode ];
6890 if ( !volume.IsLinked( n, prevSideNode ))
6894 if ( iNode ) // a node before prevSideNode
6895 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6896 else // a node after prevSideNode
6897 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6899 // check if this link was already used
6900 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6901 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6902 if (!isJustChecked &&
6903 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6905 // test a link geometrically
6906 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6907 bool linkIsBetter = false;
6908 double dot = 0.0, dist = 0.0;
6909 if ( searchByDir ) { // choose most co-directed link
6910 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6911 linkIsBetter = ( dot > maxDot );
6913 else { // choose link with the node closest to bordPos
6914 dist = ( nextXYZ - bordPos ).SquareModulus();
6915 linkIsBetter = ( dist < minDist );
6917 if ( linkIsBetter ) {
6926 } // loop on inverse elements of prevSideNode
6929 MESSAGE(" Cant find path by links of the Side 2 ");
6930 return SEW_BAD_SIDE_NODES;
6932 sideNodes.push_back( sideNode );
6933 sideElems.push_back( sideElem );
6934 foundSideLinkIDs.insert ( linkID );
6935 prevSideNode = sideNode;
6937 if ( *nBordIt == theBordLastNode )
6938 searchByDir = false;
6940 // find the next border link to compare with
6941 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6942 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6943 // move to next border node if sideNode is before forward border node (bordPos)
6944 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6945 prevBordNode = *nBordIt;
6947 bordPos = nBordXYZ[ *nBordIt ];
6948 bordDir = bordPos - nBordXYZ[ prevBordNode ];
6949 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6953 while ( sideNode != theSideSecondNode );
6955 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6956 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6957 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6959 } // end nodes search on the side 2
6961 // ============================
6962 // sew the border to the side 2
6963 // ============================
6965 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
6966 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6968 TListOfListOfNodes nodeGroupsToMerge;
6969 if ( nbNodes[0] == nbNodes[1] ||
6970 ( theSideIsFreeBorder && !theSideThirdNode)) {
6972 // all nodes are to be merged
6974 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6975 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6976 nIt[0]++, nIt[1]++ )
6978 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6979 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6980 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6985 // insert new nodes into the border and the side to get equal nb of segments
6987 // get normalized parameters of nodes on the borders
6988 //double param[ 2 ][ maxNbNodes ];
6990 param[0] = new double [ maxNbNodes ];
6991 param[1] = new double [ maxNbNodes ];
6993 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6994 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
6995 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
6996 const SMDS_MeshNode* nPrev = *nIt;
6997 double bordLength = 0;
6998 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
6999 const SMDS_MeshNode* nCur = *nIt;
7000 gp_XYZ segment (nCur->X() - nPrev->X(),
7001 nCur->Y() - nPrev->Y(),
7002 nCur->Z() - nPrev->Z());
7003 double segmentLen = segment.Modulus();
7004 bordLength += segmentLen;
7005 param[ iBord ][ iNode ] = bordLength;
7008 // normalize within [0,1]
7009 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7010 param[ iBord ][ iNode ] /= bordLength;
7014 // loop on border segments
7015 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7016 int i[ 2 ] = { 0, 0 };
7017 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7018 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7020 TElemOfNodeListMap insertMap;
7021 TElemOfNodeListMap::iterator insertMapIt;
7023 // key: elem to insert nodes into
7024 // value: 2 nodes to insert between + nodes to be inserted
7026 bool next[ 2 ] = { false, false };
7028 // find min adjacent segment length after sewing
7029 double nextParam = 10., prevParam = 0;
7030 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7031 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7032 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7033 if ( i[ iBord ] > 0 )
7034 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7036 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7037 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7038 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7040 // choose to insert or to merge nodes
7041 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7042 if ( Abs( du ) <= minSegLen * 0.2 ) {
7045 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7046 const SMDS_MeshNode* n0 = *nIt[0];
7047 const SMDS_MeshNode* n1 = *nIt[1];
7048 nodeGroupsToMerge.back().push_back( n1 );
7049 nodeGroupsToMerge.back().push_back( n0 );
7050 // position of node of the border changes due to merge
7051 param[ 0 ][ i[0] ] += du;
7052 // move n1 for the sake of elem shape evaluation during insertion.
7053 // n1 will be removed by MergeNodes() anyway
7054 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7055 next[0] = next[1] = true;
7060 int intoBord = ( du < 0 ) ? 0 : 1;
7061 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7062 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7063 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7064 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7065 if ( intoBord == 1 ) {
7066 // move node of the border to be on a link of elem of the side
7067 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7068 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7069 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7070 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7071 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7073 insertMapIt = insertMap.find( elem );
7074 bool notFound = ( insertMapIt == insertMap.end() );
7075 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7077 // insert into another link of the same element:
7078 // 1. perform insertion into the other link of the elem
7079 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7080 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7081 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7082 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7083 // 2. perform insertion into the link of adjacent faces
7085 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7087 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7091 if (toCreatePolyedrs) {
7092 // perform insertion into the links of adjacent volumes
7093 UpdateVolumes(n12, n22, nodeList);
7095 // 3. find an element appeared on n1 and n2 after the insertion
7096 insertMap.erase( elem );
7097 elem = findAdjacentFace( n1, n2, 0 );
7099 if ( notFound || otherLink ) {
7100 // add element and nodes of the side into the insertMap
7101 insertMapIt = insertMap.insert
7102 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7103 (*insertMapIt).second.push_back( n1 );
7104 (*insertMapIt).second.push_back( n2 );
7106 // add node to be inserted into elem
7107 (*insertMapIt).second.push_back( nIns );
7108 next[ 1 - intoBord ] = true;
7111 // go to the next segment
7112 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7113 if ( next[ iBord ] ) {
7114 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7116 nPrev[ iBord ] = *nIt[ iBord ];
7117 nIt[ iBord ]++; i[ iBord ]++;
7121 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7123 // perform insertion of nodes into elements
7125 for (insertMapIt = insertMap.begin();
7126 insertMapIt != insertMap.end();
7129 const SMDS_MeshElement* elem = (*insertMapIt).first;
7130 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7131 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7132 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7134 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7136 if ( !theSideIsFreeBorder ) {
7137 // look for and insert nodes into the faces adjacent to elem
7139 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7141 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7146 if (toCreatePolyedrs) {
7147 // perform insertion into the links of adjacent volumes
7148 UpdateVolumes(n1, n2, nodeList);
7154 } // end: insert new nodes
7156 MergeNodes ( nodeGroupsToMerge );
7161 //=======================================================================
7162 //function : InsertNodesIntoLink
7163 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7164 // and theBetweenNode2 and split theElement
7165 //=======================================================================
7167 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7168 const SMDS_MeshNode* theBetweenNode1,
7169 const SMDS_MeshNode* theBetweenNode2,
7170 list<const SMDS_MeshNode*>& theNodesToInsert,
7171 const bool toCreatePoly)
7173 if ( theFace->GetType() != SMDSAbs_Face ) return;
7175 // find indices of 2 link nodes and of the rest nodes
7176 int iNode = 0, il1, il2, i3, i4;
7177 il1 = il2 = i3 = i4 = -1;
7178 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7179 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7181 if(theFace->IsQuadratic()) {
7182 const SMDS_QuadraticFaceOfNodes* F =
7183 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7184 // use special nodes iterator
7185 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7186 while( anIter->more() ) {
7187 const SMDS_MeshNode* n = anIter->next();
7188 if ( n == theBetweenNode1 )
7190 else if ( n == theBetweenNode2 )
7196 nodes[ iNode++ ] = n;
7200 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7201 while ( nodeIt->more() ) {
7202 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7203 if ( n == theBetweenNode1 )
7205 else if ( n == theBetweenNode2 )
7211 nodes[ iNode++ ] = n;
7214 if ( il1 < 0 || il2 < 0 || i3 < 0 )
7217 // arrange link nodes to go one after another regarding the face orientation
7218 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7219 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7224 aNodesToInsert.reverse();
7226 // check that not link nodes of a quadrangles are in good order
7227 int nbFaceNodes = theFace->NbNodes();
7228 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7234 if (toCreatePoly || theFace->IsPoly()) {
7237 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7239 // add nodes of face up to first node of link
7242 if(theFace->IsQuadratic()) {
7243 const SMDS_QuadraticFaceOfNodes* F =
7244 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7245 // use special nodes iterator
7246 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7247 while( anIter->more() && !isFLN ) {
7248 const SMDS_MeshNode* n = anIter->next();
7249 poly_nodes[iNode++] = n;
7250 if (n == nodes[il1]) {
7254 // add nodes to insert
7255 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7256 for (; nIt != aNodesToInsert.end(); nIt++) {
7257 poly_nodes[iNode++] = *nIt;
7259 // add nodes of face starting from last node of link
7260 while ( anIter->more() ) {
7261 poly_nodes[iNode++] = anIter->next();
7265 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7266 while ( nodeIt->more() && !isFLN ) {
7267 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7268 poly_nodes[iNode++] = n;
7269 if (n == nodes[il1]) {
7273 // add nodes to insert
7274 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7275 for (; nIt != aNodesToInsert.end(); nIt++) {
7276 poly_nodes[iNode++] = *nIt;
7278 // add nodes of face starting from last node of link
7279 while ( nodeIt->more() ) {
7280 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7281 poly_nodes[iNode++] = n;
7285 // edit or replace the face
7286 SMESHDS_Mesh *aMesh = GetMeshDS();
7288 if (theFace->IsPoly()) {
7289 aMesh->ChangePolygonNodes(theFace, poly_nodes);
7292 int aShapeId = FindShape( theFace );
7294 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7295 myLastCreatedElems.Append(newElem);
7296 if ( aShapeId && newElem )
7297 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7299 aMesh->RemoveElement(theFace);
7304 if( !theFace->IsQuadratic() ) {
7306 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7307 int nbLinkNodes = 2 + aNodesToInsert.size();
7308 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7309 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7310 linkNodes[ 0 ] = nodes[ il1 ];
7311 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7312 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7313 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7314 linkNodes[ iNode++ ] = *nIt;
7316 // decide how to split a quadrangle: compare possible variants
7317 // and choose which of splits to be a quadrangle
7318 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7319 if ( nbFaceNodes == 3 ) {
7320 iBestQuad = nbSplits;
7323 else if ( nbFaceNodes == 4 ) {
7324 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7325 double aBestRate = DBL_MAX;
7326 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7328 double aBadRate = 0;
7329 // evaluate elements quality
7330 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7331 if ( iSplit == iQuad ) {
7332 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7336 aBadRate += getBadRate( &quad, aCrit );
7339 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7341 nodes[ iSplit < iQuad ? i4 : i3 ]);
7342 aBadRate += getBadRate( &tria, aCrit );
7346 if ( aBadRate < aBestRate ) {
7348 aBestRate = aBadRate;
7353 // create new elements
7354 SMESHDS_Mesh *aMesh = GetMeshDS();
7355 int aShapeId = FindShape( theFace );
7358 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7359 SMDS_MeshElement* newElem = 0;
7360 if ( iSplit == iBestQuad )
7361 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7366 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7368 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7369 myLastCreatedElems.Append(newElem);
7370 if ( aShapeId && newElem )
7371 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7374 // change nodes of theFace
7375 const SMDS_MeshNode* newNodes[ 4 ];
7376 newNodes[ 0 ] = linkNodes[ i1 ];
7377 newNodes[ 1 ] = linkNodes[ i2 ];
7378 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7379 newNodes[ 3 ] = nodes[ i4 ];
7380 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7381 } // end if(!theFace->IsQuadratic())
7382 else { // theFace is quadratic
7383 // we have to split theFace on simple triangles and one simple quadrangle
7385 int nbshift = tmp*2;
7386 // shift nodes in nodes[] by nbshift
7388 for(i=0; i<nbshift; i++) {
7389 const SMDS_MeshNode* n = nodes[0];
7390 for(j=0; j<nbFaceNodes-1; j++) {
7391 nodes[j] = nodes[j+1];
7393 nodes[nbFaceNodes-1] = n;
7395 il1 = il1 - nbshift;
7396 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7397 // n0 n1 n2 n0 n1 n2
7398 // +-----+-----+ +-----+-----+
7407 // create new elements
7408 SMESHDS_Mesh *aMesh = GetMeshDS();
7409 int aShapeId = FindShape( theFace );
7412 if(nbFaceNodes==6) { // quadratic triangle
7413 SMDS_MeshElement* newElem =
7414 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7415 myLastCreatedElems.Append(newElem);
7416 if ( aShapeId && newElem )
7417 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7418 if(theFace->IsMediumNode(nodes[il1])) {
7419 // create quadrangle
7420 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
7421 myLastCreatedElems.Append(newElem);
7422 if ( aShapeId && newElem )
7423 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7429 // create quadrangle
7430 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
7431 myLastCreatedElems.Append(newElem);
7432 if ( aShapeId && newElem )
7433 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7439 else { // nbFaceNodes==8 - quadratic quadrangle
7440 SMDS_MeshElement* newElem =
7441 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7442 myLastCreatedElems.Append(newElem);
7443 if ( aShapeId && newElem )
7444 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7445 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
7446 myLastCreatedElems.Append(newElem);
7447 if ( aShapeId && newElem )
7448 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7449 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
7450 myLastCreatedElems.Append(newElem);
7451 if ( aShapeId && newElem )
7452 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7453 if(theFace->IsMediumNode(nodes[il1])) {
7454 // create quadrangle
7455 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
7456 myLastCreatedElems.Append(newElem);
7457 if ( aShapeId && newElem )
7458 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7464 // create quadrangle
7465 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7466 myLastCreatedElems.Append(newElem);
7467 if ( aShapeId && newElem )
7468 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7474 // create needed triangles using n1,n2,n3 and inserted nodes
7475 int nbn = 2 + aNodesToInsert.size();
7476 //const SMDS_MeshNode* aNodes[nbn];
7477 vector<const SMDS_MeshNode*> aNodes(nbn);
7478 aNodes[0] = nodes[n1];
7479 aNodes[nbn-1] = nodes[n2];
7480 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7481 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7482 aNodes[iNode++] = *nIt;
7484 for(i=1; i<nbn; i++) {
7485 SMDS_MeshElement* newElem =
7486 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7487 myLastCreatedElems.Append(newElem);
7488 if ( aShapeId && newElem )
7489 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7491 // remove old quadratic face
7492 aMesh->RemoveElement(theFace);
7496 //=======================================================================
7497 //function : UpdateVolumes
7499 //=======================================================================
7500 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
7501 const SMDS_MeshNode* theBetweenNode2,
7502 list<const SMDS_MeshNode*>& theNodesToInsert)
7504 myLastCreatedElems.Clear();
7505 myLastCreatedNodes.Clear();
7507 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7508 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7509 const SMDS_MeshElement* elem = invElemIt->next();
7511 // check, if current volume has link theBetweenNode1 - theBetweenNode2
7512 SMDS_VolumeTool aVolume (elem);
7513 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7516 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7517 int iface, nbFaces = aVolume.NbFaces();
7518 vector<const SMDS_MeshNode *> poly_nodes;
7519 vector<int> quantities (nbFaces);
7521 for (iface = 0; iface < nbFaces; iface++) {
7522 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7523 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7524 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7526 for (int inode = 0; inode < nbFaceNodes; inode++) {
7527 poly_nodes.push_back(faceNodes[inode]);
7529 if (nbInserted == 0) {
7530 if (faceNodes[inode] == theBetweenNode1) {
7531 if (faceNodes[inode + 1] == theBetweenNode2) {
7532 nbInserted = theNodesToInsert.size();
7534 // add nodes to insert
7535 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7536 for (; nIt != theNodesToInsert.end(); nIt++) {
7537 poly_nodes.push_back(*nIt);
7541 else if (faceNodes[inode] == theBetweenNode2) {
7542 if (faceNodes[inode + 1] == theBetweenNode1) {
7543 nbInserted = theNodesToInsert.size();
7545 // add nodes to insert in reversed order
7546 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7548 for (; nIt != theNodesToInsert.begin(); nIt--) {
7549 poly_nodes.push_back(*nIt);
7551 poly_nodes.push_back(*nIt);
7558 quantities[iface] = nbFaceNodes + nbInserted;
7561 // Replace or update the volume
7562 SMESHDS_Mesh *aMesh = GetMeshDS();
7564 if (elem->IsPoly()) {
7565 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7569 int aShapeId = FindShape( elem );
7571 SMDS_MeshElement* newElem =
7572 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7573 myLastCreatedElems.Append(newElem);
7574 if (aShapeId && newElem)
7575 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7577 aMesh->RemoveElement(elem);
7582 //=======================================================================
7584 * \brief Convert elements contained in a submesh to quadratic
7585 * \retval int - nb of checked elements
7587 //=======================================================================
7589 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
7590 SMESH_MesherHelper& theHelper,
7591 const bool theForce3d)
7594 if( !theSm ) return nbElem;
7596 const bool notFromGroups = false;
7597 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7598 while(ElemItr->more())
7601 const SMDS_MeshElement* elem = ElemItr->next();
7602 if( !elem || elem->IsQuadratic() ) continue;
7604 int id = elem->GetID();
7605 int nbNodes = elem->NbNodes();
7606 vector<const SMDS_MeshNode *> aNds (nbNodes);
7608 for(int i = 0; i < nbNodes; i++)
7610 aNds[i] = elem->GetNode(i);
7612 SMDSAbs_ElementType aType = elem->GetType();
7614 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7616 const SMDS_MeshElement* NewElem = 0;
7622 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7630 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7633 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7640 case SMDSAbs_Volume :
7645 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7648 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7651 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7652 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7662 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7664 theSm->AddElement( NewElem );
7669 //=======================================================================
7670 //function : ConvertToQuadratic
7672 //=======================================================================
7673 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7675 SMESHDS_Mesh* meshDS = GetMeshDS();
7677 SMESH_MesherHelper aHelper(*myMesh);
7678 aHelper.SetIsQuadratic( true );
7679 const bool notFromGroups = false;
7681 int nbCheckedElems = 0;
7682 if ( myMesh->HasShapeToMesh() )
7684 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7686 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7687 while ( smIt->more() ) {
7688 SMESH_subMesh* sm = smIt->next();
7689 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7690 aHelper.SetSubShape( sm->GetSubShape() );
7691 if ( !theForce3d) aHelper.SetCheckNodePosition(true);
7692 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7697 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7698 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7700 SMESHDS_SubMesh *smDS = 0;
7701 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7702 while(aEdgeItr->more())
7704 const SMDS_MeshEdge* edge = aEdgeItr->next();
7705 if(edge && !edge->IsQuadratic())
7707 int id = edge->GetID();
7708 const SMDS_MeshNode* n1 = edge->GetNode(0);
7709 const SMDS_MeshNode* n2 = edge->GetNode(1);
7711 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7713 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7714 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7717 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7718 while(aFaceItr->more())
7720 const SMDS_MeshFace* face = aFaceItr->next();
7721 if(!face || face->IsQuadratic() ) continue;
7723 int id = face->GetID();
7724 int nbNodes = face->NbNodes();
7725 vector<const SMDS_MeshNode *> aNds (nbNodes);
7727 for(int i = 0; i < nbNodes; i++)
7729 aNds[i] = face->GetNode(i);
7732 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7734 SMDS_MeshFace * NewFace = 0;
7738 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7741 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7746 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7748 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7749 while(aVolumeItr->more())
7751 const SMDS_MeshVolume* volume = aVolumeItr->next();
7752 if(!volume || volume->IsQuadratic() ) continue;
7754 int id = volume->GetID();
7755 int nbNodes = volume->NbNodes();
7756 vector<const SMDS_MeshNode *> aNds (nbNodes);
7758 for(int i = 0; i < nbNodes; i++)
7760 aNds[i] = volume->GetNode(i);
7763 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7765 SMDS_MeshVolume * NewVolume = 0;
7769 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7770 aNds[3], id, theForce3d );
7773 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7774 aNds[3], aNds[4], aNds[5], id, theForce3d);
7777 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7778 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7783 ReplaceElemInGroups(volume, NewVolume, meshDS);
7786 if ( !theForce3d ) {
7787 aHelper.SetSubShape(0); // apply to the whole mesh
7788 aHelper.FixQuadraticElements();
7792 //=======================================================================
7794 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7795 * \retval int - nb of checked elements
7797 //=======================================================================
7799 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7800 SMDS_ElemIteratorPtr theItr,
7801 const int theShapeID)
7804 SMESHDS_Mesh* meshDS = GetMeshDS();
7805 const bool notFromGroups = false;
7807 while( theItr->more() )
7809 const SMDS_MeshElement* elem = theItr->next();
7811 if( elem && elem->IsQuadratic())
7813 int id = elem->GetID();
7814 int nbNodes = elem->NbNodes();
7815 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7816 aNds.reserve( nbNodes );
7817 mediumNodes.reserve( nbNodes );
7819 for(int i = 0; i < nbNodes; i++)
7821 const SMDS_MeshNode* n = elem->GetNode(i);
7823 if( elem->IsMediumNode( n ) )
7824 mediumNodes.push_back( n );
7826 aNds.push_back( n );
7828 if( aNds.empty() ) continue;
7829 SMDSAbs_ElementType aType = elem->GetType();
7831 //remove old quadratic element
7832 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7834 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7835 ReplaceElemInGroups(elem, NewElem, meshDS);
7836 if( theSm && NewElem )
7837 theSm->AddElement( NewElem );
7839 // remove medium nodes
7840 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7841 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7842 const SMDS_MeshNode* n = *nIt;
7843 if ( n->NbInverseElements() == 0 ) {
7844 if ( n->GetPosition()->GetShapeId() != theShapeID )
7845 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7846 ( n->GetPosition()->GetShapeId() ));
7848 meshDS->RemoveFreeNode( n, theSm );
7856 //=======================================================================
7857 //function : ConvertFromQuadratic
7859 //=======================================================================
7860 bool SMESH_MeshEditor::ConvertFromQuadratic()
7862 int nbCheckedElems = 0;
7863 if ( myMesh->HasShapeToMesh() )
7865 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7867 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7868 while ( smIt->more() ) {
7869 SMESH_subMesh* sm = smIt->next();
7870 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7871 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7877 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7878 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7880 SMESHDS_SubMesh *aSM = 0;
7881 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7887 //=======================================================================
7888 //function : SewSideElements
7890 //=======================================================================
7892 SMESH_MeshEditor::Sew_Error
7893 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7894 TIDSortedElemSet& theSide2,
7895 const SMDS_MeshNode* theFirstNode1,
7896 const SMDS_MeshNode* theFirstNode2,
7897 const SMDS_MeshNode* theSecondNode1,
7898 const SMDS_MeshNode* theSecondNode2)
7900 myLastCreatedElems.Clear();
7901 myLastCreatedNodes.Clear();
7903 MESSAGE ("::::SewSideElements()");
7904 if ( theSide1.size() != theSide2.size() )
7905 return SEW_DIFF_NB_OF_ELEMENTS;
7907 Sew_Error aResult = SEW_OK;
7909 // 1. Build set of faces representing each side
7910 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7911 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7913 // =======================================================================
7914 // 1. Build set of faces representing each side:
7915 // =======================================================================
7916 // a. build set of nodes belonging to faces
7917 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7918 // c. create temporary faces representing side of volumes if correspondent
7919 // face does not exist
7921 SMESHDS_Mesh* aMesh = GetMeshDS();
7922 SMDS_Mesh aTmpFacesMesh;
7923 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7924 set<const SMDS_MeshElement*> volSet1, volSet2;
7925 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7926 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7927 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7928 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7929 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7930 int iSide, iFace, iNode;
7932 for ( iSide = 0; iSide < 2; iSide++ ) {
7933 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7934 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7935 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7936 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7937 set<const SMDS_MeshElement*>::iterator vIt;
7938 TIDSortedElemSet::iterator eIt;
7939 set<const SMDS_MeshNode*>::iterator nIt;
7941 // check that given nodes belong to given elements
7942 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7943 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7944 int firstIndex = -1, secondIndex = -1;
7945 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7946 const SMDS_MeshElement* elem = *eIt;
7947 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
7948 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7949 if ( firstIndex > -1 && secondIndex > -1 ) break;
7951 if ( firstIndex < 0 || secondIndex < 0 ) {
7952 // we can simply return until temporary faces created
7953 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7956 // -----------------------------------------------------------
7957 // 1a. Collect nodes of existing faces
7958 // and build set of face nodes in order to detect missing
7959 // faces corresponing to sides of volumes
7960 // -----------------------------------------------------------
7962 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7964 // loop on the given element of a side
7965 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7966 //const SMDS_MeshElement* elem = *eIt;
7967 const SMDS_MeshElement* elem = *eIt;
7968 if ( elem->GetType() == SMDSAbs_Face ) {
7969 faceSet->insert( elem );
7970 set <const SMDS_MeshNode*> faceNodeSet;
7971 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7972 while ( nodeIt->more() ) {
7973 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7974 nodeSet->insert( n );
7975 faceNodeSet.insert( n );
7977 setOfFaceNodeSet.insert( faceNodeSet );
7979 else if ( elem->GetType() == SMDSAbs_Volume )
7980 volSet->insert( elem );
7982 // ------------------------------------------------------------------------------
7983 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
7984 // ------------------------------------------------------------------------------
7986 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7987 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7988 while ( fIt->more() ) { // loop on faces sharing a node
7989 const SMDS_MeshElement* f = fIt->next();
7990 if ( faceSet->find( f ) == faceSet->end() ) {
7991 // check if all nodes are in nodeSet and
7992 // complete setOfFaceNodeSet if they are
7993 set <const SMDS_MeshNode*> faceNodeSet;
7994 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7995 bool allInSet = true;
7996 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7997 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7998 if ( nodeSet->find( n ) == nodeSet->end() )
8001 faceNodeSet.insert( n );
8004 faceSet->insert( f );
8005 setOfFaceNodeSet.insert( faceNodeSet );
8011 // -------------------------------------------------------------------------
8012 // 1c. Create temporary faces representing sides of volumes if correspondent
8013 // face does not exist
8014 // -------------------------------------------------------------------------
8016 if ( !volSet->empty() ) {
8017 //int nodeSetSize = nodeSet->size();
8019 // loop on given volumes
8020 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8021 SMDS_VolumeTool vol (*vIt);
8022 // loop on volume faces: find free faces
8023 // --------------------------------------
8024 list<const SMDS_MeshElement* > freeFaceList;
8025 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8026 if ( !vol.IsFreeFace( iFace ))
8028 // check if there is already a face with same nodes in a face set
8029 const SMDS_MeshElement* aFreeFace = 0;
8030 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8031 int nbNodes = vol.NbFaceNodes( iFace );
8032 set <const SMDS_MeshNode*> faceNodeSet;
8033 vol.GetFaceNodes( iFace, faceNodeSet );
8034 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8036 // no such a face is given but it still can exist, check it
8037 if ( nbNodes == 3 ) {
8038 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8040 else if ( nbNodes == 4 ) {
8041 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8044 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8045 aFreeFace = aMesh->FindFace(poly_nodes);
8049 // create a temporary face
8050 if ( nbNodes == 3 ) {
8051 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8053 else if ( nbNodes == 4 ) {
8054 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8057 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8058 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8062 freeFaceList.push_back( aFreeFace );
8064 } // loop on faces of a volume
8066 // choose one of several free faces
8067 // --------------------------------------
8068 if ( freeFaceList.size() > 1 ) {
8069 // choose a face having max nb of nodes shared by other elems of a side
8070 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8071 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8072 while ( fIt != freeFaceList.end() ) { // loop on free faces
8073 int nbSharedNodes = 0;
8074 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8075 while ( nodeIt->more() ) { // loop on free face nodes
8076 const SMDS_MeshNode* n =
8077 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8078 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8079 while ( invElemIt->more() ) {
8080 const SMDS_MeshElement* e = invElemIt->next();
8081 if ( faceSet->find( e ) != faceSet->end() )
8083 if ( elemSet->find( e ) != elemSet->end() )
8087 if ( nbSharedNodes >= maxNbNodes ) {
8088 maxNbNodes = nbSharedNodes;
8092 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8094 if ( freeFaceList.size() > 1 )
8096 // could not choose one face, use another way
8097 // choose a face most close to the bary center of the opposite side
8098 gp_XYZ aBC( 0., 0., 0. );
8099 set <const SMDS_MeshNode*> addedNodes;
8100 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8101 eIt = elemSet2->begin();
8102 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8103 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8104 while ( nodeIt->more() ) { // loop on free face nodes
8105 const SMDS_MeshNode* n =
8106 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8107 if ( addedNodes.insert( n ).second )
8108 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8111 aBC /= addedNodes.size();
8112 double minDist = DBL_MAX;
8113 fIt = freeFaceList.begin();
8114 while ( fIt != freeFaceList.end() ) { // loop on free faces
8116 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8117 while ( nodeIt->more() ) { // loop on free face nodes
8118 const SMDS_MeshNode* n =
8119 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8120 gp_XYZ p( n->X(),n->Y(),n->Z() );
8121 dist += ( aBC - p ).SquareModulus();
8123 if ( dist < minDist ) {
8125 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8128 fIt = freeFaceList.erase( fIt++ );
8131 } // choose one of several free faces of a volume
8133 if ( freeFaceList.size() == 1 ) {
8134 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8135 faceSet->insert( aFreeFace );
8136 // complete a node set with nodes of a found free face
8137 // for ( iNode = 0; iNode < ; iNode++ )
8138 // nodeSet->insert( fNodes[ iNode ] );
8141 } // loop on volumes of a side
8143 // // complete a set of faces if new nodes in a nodeSet appeared
8144 // // ----------------------------------------------------------
8145 // if ( nodeSetSize != nodeSet->size() ) {
8146 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8147 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8148 // while ( fIt->more() ) { // loop on faces sharing a node
8149 // const SMDS_MeshElement* f = fIt->next();
8150 // if ( faceSet->find( f ) == faceSet->end() ) {
8151 // // check if all nodes are in nodeSet and
8152 // // complete setOfFaceNodeSet if they are
8153 // set <const SMDS_MeshNode*> faceNodeSet;
8154 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8155 // bool allInSet = true;
8156 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8157 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8158 // if ( nodeSet->find( n ) == nodeSet->end() )
8159 // allInSet = false;
8161 // faceNodeSet.insert( n );
8163 // if ( allInSet ) {
8164 // faceSet->insert( f );
8165 // setOfFaceNodeSet.insert( faceNodeSet );
8171 } // Create temporary faces, if there are volumes given
8174 if ( faceSet1.size() != faceSet2.size() ) {
8175 // delete temporary faces: they are in reverseElements of actual nodes
8176 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8177 while ( tmpFaceIt->more() )
8178 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8179 MESSAGE("Diff nb of faces");
8180 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8183 // ============================================================
8184 // 2. Find nodes to merge:
8185 // bind a node to remove to a node to put instead
8186 // ============================================================
8188 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
8189 if ( theFirstNode1 != theFirstNode2 )
8190 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
8191 if ( theSecondNode1 != theSecondNode2 )
8192 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
8194 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8195 set< long > linkIdSet; // links to process
8196 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
8198 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
8199 list< NLink > linkList[2];
8200 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8201 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8202 // loop on links in linkList; find faces by links and append links
8203 // of the found faces to linkList
8204 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8205 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8206 NLink link[] = { *linkIt[0], *linkIt[1] };
8207 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
8208 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
8211 // by links, find faces in the face sets,
8212 // and find indices of link nodes in the found faces;
8213 // in a face set, there is only one or no face sharing a link
8214 // ---------------------------------------------------------------
8216 const SMDS_MeshElement* face[] = { 0, 0 };
8217 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
8218 vector<const SMDS_MeshNode*> fnodes1(9);
8219 vector<const SMDS_MeshNode*> fnodes2(9);
8220 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
8221 vector<const SMDS_MeshNode*> notLinkNodes1(6);
8222 vector<const SMDS_MeshNode*> notLinkNodes2(6);
8223 int iLinkNode[2][2];
8224 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8225 const SMDS_MeshNode* n1 = link[iSide].first;
8226 const SMDS_MeshNode* n2 = link[iSide].second;
8227 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8228 set< const SMDS_MeshElement* > fMap;
8229 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
8230 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
8231 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8232 while ( fIt->more() ) { // loop on faces sharing a node
8233 const SMDS_MeshElement* f = fIt->next();
8234 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8235 ! fMap.insert( f ).second ) // f encounters twice
8237 if ( face[ iSide ] ) {
8238 MESSAGE( "2 faces per link " );
8239 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
8243 faceSet->erase( f );
8244 // get face nodes and find ones of a link
8249 fnodes1.resize(f->NbNodes()+1);
8250 notLinkNodes1.resize(f->NbNodes()-2);
8253 fnodes2.resize(f->NbNodes()+1);
8254 notLinkNodes2.resize(f->NbNodes()-2);
8257 if(!f->IsQuadratic()) {
8258 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
8259 while ( nIt->more() ) {
8260 const SMDS_MeshNode* n =
8261 static_cast<const SMDS_MeshNode*>( nIt->next() );
8263 iLinkNode[ iSide ][ 0 ] = iNode;
8265 else if ( n == n2 ) {
8266 iLinkNode[ iSide ][ 1 ] = iNode;
8268 //else if ( notLinkNodes[ iSide ][ 0 ] )
8269 // notLinkNodes[ iSide ][ 1 ] = n;
8271 // notLinkNodes[ iSide ][ 0 ] = n;
8275 notLinkNodes1[nbl] = n;
8276 //notLinkNodes1.push_back(n);
8278 notLinkNodes2[nbl] = n;
8279 //notLinkNodes2.push_back(n);
8281 //faceNodes[ iSide ][ iNode++ ] = n;
8283 fnodes1[iNode++] = n;
8286 fnodes2[iNode++] = n;
8290 else { // f->IsQuadratic()
8291 const SMDS_QuadraticFaceOfNodes* F =
8292 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
8293 // use special nodes iterator
8294 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8295 while ( anIter->more() ) {
8296 const SMDS_MeshNode* n =
8297 static_cast<const SMDS_MeshNode*>( anIter->next() );
8299 iLinkNode[ iSide ][ 0 ] = iNode;
8301 else if ( n == n2 ) {
8302 iLinkNode[ iSide ][ 1 ] = iNode;
8307 notLinkNodes1[nbl] = n;
8310 notLinkNodes2[nbl] = n;
8314 fnodes1[iNode++] = n;
8317 fnodes2[iNode++] = n;
8321 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
8323 fnodes1[iNode] = fnodes1[0];
8326 fnodes2[iNode] = fnodes1[0];
8333 // check similarity of elements of the sides
8334 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8335 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8336 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8337 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8340 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8342 break; // do not return because it s necessary to remove tmp faces
8345 // set nodes to merge
8346 // -------------------
8348 if ( face[0] && face[1] ) {
8349 int nbNodes = face[0]->NbNodes();
8350 if ( nbNodes != face[1]->NbNodes() ) {
8351 MESSAGE("Diff nb of face nodes");
8352 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8353 break; // do not return because it s necessary to remove tmp faces
8355 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
8356 if ( nbNodes == 3 ) {
8357 //nReplaceMap.insert( TNodeNodeMap::value_type
8358 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8359 nReplaceMap.insert( TNodeNodeMap::value_type
8360 ( notLinkNodes1[0], notLinkNodes2[0] ));
8363 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8364 // analyse link orientation in faces
8365 int i1 = iLinkNode[ iSide ][ 0 ];
8366 int i2 = iLinkNode[ iSide ][ 1 ];
8367 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
8368 // if notLinkNodes are the first and the last ones, then
8369 // their order does not correspond to the link orientation
8370 if (( i1 == 1 && i2 == 2 ) ||
8371 ( i1 == 2 && i2 == 1 ))
8372 reverse[ iSide ] = !reverse[ iSide ];
8374 if ( reverse[0] == reverse[1] ) {
8375 //nReplaceMap.insert( TNodeNodeMap::value_type
8376 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8377 //nReplaceMap.insert( TNodeNodeMap::value_type
8378 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
8379 for(int nn=0; nn<nbNodes-2; nn++) {
8380 nReplaceMap.insert( TNodeNodeMap::value_type
8381 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
8385 //nReplaceMap.insert( TNodeNodeMap::value_type
8386 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
8387 //nReplaceMap.insert( TNodeNodeMap::value_type
8388 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
8389 for(int nn=0; nn<nbNodes-2; nn++) {
8390 nReplaceMap.insert( TNodeNodeMap::value_type
8391 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
8396 // add other links of the faces to linkList
8397 // -----------------------------------------
8399 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
8400 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8401 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
8402 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
8403 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
8404 if ( !iter_isnew.second ) { // already in a set: no need to process
8405 linkIdSet.erase( iter_isnew.first );
8407 else // new in set == encountered for the first time: add
8409 //const SMDS_MeshNode* n1 = nodes[ iNode ];
8410 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
8411 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
8412 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
8413 linkList[0].push_back ( NLink( n1, n2 ));
8414 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8418 } // loop on link lists
8420 if ( aResult == SEW_OK &&
8421 ( linkIt[0] != linkList[0].end() ||
8422 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
8423 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
8424 " " << (faceSetPtr[1]->empty()));
8425 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8428 // ====================================================================
8429 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8430 // ====================================================================
8432 // delete temporary faces: they are in reverseElements of actual nodes
8433 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8434 while ( tmpFaceIt->more() )
8435 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8437 if ( aResult != SEW_OK)
8440 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
8441 // loop on nodes replacement map
8442 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
8443 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
8444 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
8445 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
8446 nodeIDsToRemove.push_back( nToRemove->GetID() );
8447 // loop on elements sharing nToRemove
8448 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
8449 while ( invElemIt->more() ) {
8450 const SMDS_MeshElement* e = invElemIt->next();
8451 // get a new suite of nodes: make replacement
8452 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
8453 vector< const SMDS_MeshNode*> nodes( nbNodes );
8454 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8455 while ( nIt->more() ) {
8456 const SMDS_MeshNode* n =
8457 static_cast<const SMDS_MeshNode*>( nIt->next() );
8458 nnIt = nReplaceMap.find( n );
8459 if ( nnIt != nReplaceMap.end() ) {
8465 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8466 // elemIDsToRemove.push_back( e->GetID() );
8469 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8473 Remove( nodeIDsToRemove, true );
8478 //================================================================================
8480 * \brief Find corresponding nodes in two sets of faces
8481 * \param theSide1 - first face set
8482 * \param theSide2 - second first face
8483 * \param theFirstNode1 - a boundary node of set 1
8484 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8485 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8486 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8487 * \param nReplaceMap - output map of corresponding nodes
8488 * \retval bool - is a success or not
8490 //================================================================================
8493 //#define DEBUG_MATCHING_NODES
8496 SMESH_MeshEditor::Sew_Error
8497 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8498 set<const SMDS_MeshElement*>& theSide2,
8499 const SMDS_MeshNode* theFirstNode1,
8500 const SMDS_MeshNode* theFirstNode2,
8501 const SMDS_MeshNode* theSecondNode1,
8502 const SMDS_MeshNode* theSecondNode2,
8503 TNodeNodeMap & nReplaceMap)
8505 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8507 nReplaceMap.clear();
8508 if ( theFirstNode1 != theFirstNode2 )
8509 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8510 if ( theSecondNode1 != theSecondNode2 )
8511 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8513 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8514 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8516 list< NLink > linkList[2];
8517 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8518 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8520 // loop on links in linkList; find faces by links and append links
8521 // of the found faces to linkList
8522 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8523 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8524 NLink link[] = { *linkIt[0], *linkIt[1] };
8525 if ( linkSet.find( link[0] ) == linkSet.end() )
8528 // by links, find faces in the face sets,
8529 // and find indices of link nodes in the found faces;
8530 // in a face set, there is only one or no face sharing a link
8531 // ---------------------------------------------------------------
8533 const SMDS_MeshElement* face[] = { 0, 0 };
8534 list<const SMDS_MeshNode*> notLinkNodes[2];
8535 //bool reverse[] = { false, false }; // order of notLinkNodes
8537 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8539 const SMDS_MeshNode* n1 = link[iSide].first;
8540 const SMDS_MeshNode* n2 = link[iSide].second;
8541 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8542 set< const SMDS_MeshElement* > facesOfNode1;
8543 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8545 // during a loop of the first node, we find all faces around n1,
8546 // during a loop of the second node, we find one face sharing both n1 and n2
8547 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8548 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8549 while ( fIt->more() ) { // loop on faces sharing a node
8550 const SMDS_MeshElement* f = fIt->next();
8551 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8552 ! facesOfNode1.insert( f ).second ) // f encounters twice
8554 if ( face[ iSide ] ) {
8555 MESSAGE( "2 faces per link " );
8556 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8559 faceSet->erase( f );
8561 // get not link nodes
8562 int nbN = f->NbNodes();
8563 if ( f->IsQuadratic() )
8565 nbNodes[ iSide ] = nbN;
8566 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8567 int i1 = f->GetNodeIndex( n1 );
8568 int i2 = f->GetNodeIndex( n2 );
8569 int iEnd = nbN, iBeg = -1, iDelta = 1;
8570 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8572 std::swap( iEnd, iBeg ); iDelta = -1;
8577 if ( i == iEnd ) i = iBeg + iDelta;
8578 if ( i == i1 ) break;
8579 nodes.push_back ( f->GetNode( i ) );
8585 // check similarity of elements of the sides
8586 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8587 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8588 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8589 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8592 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8596 // set nodes to merge
8597 // -------------------
8599 if ( face[0] && face[1] ) {
8600 if ( nbNodes[0] != nbNodes[1] ) {
8601 MESSAGE("Diff nb of face nodes");
8602 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8604 #ifdef DEBUG_MATCHING_NODES
8605 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8606 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8607 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8609 int nbN = nbNodes[0];
8611 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8612 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8613 for ( int i = 0 ; i < nbN - 2; ++i ) {
8614 #ifdef DEBUG_MATCHING_NODES
8615 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8617 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8621 // add other links of the face 1 to linkList
8622 // -----------------------------------------
8624 const SMDS_MeshElement* f0 = face[0];
8625 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8626 for ( int i = 0; i < nbN; i++ )
8628 const SMDS_MeshNode* n2 = f0->GetNode( i );
8629 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8630 linkSet.insert( SMESH_TLink( n1, n2 ));
8631 if ( !iter_isnew.second ) { // already in a set: no need to process
8632 linkSet.erase( iter_isnew.first );
8634 else // new in set == encountered for the first time: add
8636 #ifdef DEBUG_MATCHING_NODES
8637 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8638 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8640 linkList[0].push_back ( NLink( n1, n2 ));
8641 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8646 } // loop on link lists
8652 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8653 \param theElems - the list of elements (edges or faces) to be replicated
8654 The nodes for duplication could be found from these elements
8655 \param theNodesNot - list of nodes to NOT replicate
8656 \param theAffectedElems - the list of elements (cells and edges) to which the
8657 replicated nodes should be associated to.
8658 \return TRUE if operation has been completed successfully, FALSE otherwise
8660 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
8661 const TIDSortedElemSet& theNodesNot,
8662 const TIDSortedElemSet& theAffectedElems )
8664 myLastCreatedElems.Clear();
8665 myLastCreatedNodes.Clear();
8667 if ( theElems.size() == 0 )
8670 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8675 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8676 // duplicate elements and nodes
8677 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
8678 // replce nodes by duplications
8679 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
8684 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8685 \param theMeshDS - mesh instance
8686 \param theElems - the elements replicated or modified (nodes should be changed)
8687 \param theNodesNot - nodes to NOT replicate
8688 \param theNodeNodeMap - relation of old node to new created node
8689 \param theIsDoubleElem - flag os to replicate element or modify
8690 \return TRUE if operation has been completed successfully, FALSE otherwise
8692 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
8693 const TIDSortedElemSet& theElems,
8694 const TIDSortedElemSet& theNodesNot,
8695 std::map< const SMDS_MeshNode*,
8696 const SMDS_MeshNode* >& theNodeNodeMap,
8697 const bool theIsDoubleElem )
8699 // iterate on through element and duplicate them (by nodes duplication)
8701 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8702 for ( ; elemItr != theElems.end(); ++elemItr )
8704 const SMDS_MeshElement* anElem = *elemItr;
8708 bool isDuplicate = false;
8709 // duplicate nodes to duplicate element
8710 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
8711 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8713 while ( anIter->more() )
8716 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8717 SMDS_MeshNode* aNewNode = aCurrNode;
8718 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
8719 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
8720 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
8723 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
8724 theNodeNodeMap[ aCurrNode ] = aNewNode;
8725 myLastCreatedNodes.Append( aNewNode );
8727 isDuplicate |= (aCurrNode == aNewNode);
8728 newNodes[ ind++ ] = aNewNode;
8733 if ( theIsDoubleElem )
8734 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
8736 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
8744 \brief Check if element located inside shape
8745 \return TRUE if IN or ON shape, FALSE otherwise
8748 static bool isInside(const SMDS_MeshElement* theElem,
8749 BRepClass3d_SolidClassifier& theBsc3d,
8750 const double theTol)
8752 gp_XYZ centerXYZ (0, 0, 0);
8753 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
8754 while (aNodeItr->more())
8756 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
8757 centerXYZ += gp_XYZ(aNode->X(), aNode->Y(), aNode->Z());
8759 gp_Pnt aPnt(centerXYZ);
8760 theBsc3d.Perform(aPnt, theTol);
8761 TopAbs_State aState = theBsc3d.State();
8762 return (aState == TopAbs_IN || aState == TopAbs_ON );
8766 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8767 \param theElems - group of of elements (edges or faces) to be replicated
8768 \param theNodesNot - group of nodes not to replicated
8769 \param theShape - shape to detect affected elements (element which geometric center
8770 located on or inside shape).
8771 The replicated nodes should be associated to affected elements.
8772 \return TRUE if operation has been completed successfully, FALSE otherwise
8775 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
8776 const TIDSortedElemSet& theNodesNot,
8777 const TopoDS_Shape& theShape )
8779 if ( theShape.IsNull() )
8782 const double aTol = Precision::Confusion();
8783 BRepClass3d_SolidClassifier bsc3d(theShape);
8784 bsc3d.PerformInfinitePoint(aTol);
8786 // iterates on indicated elements and get elements by back references from their nodes
8787 TIDSortedElemSet anAffected;
8788 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8789 for ( ; elemItr != theElems.end(); ++elemItr )
8791 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
8795 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
8796 while ( nodeItr->more() )
8798 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
8799 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
8801 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
8802 while ( backElemItr->more() )
8804 SMDS_MeshElement* curElem = (SMDS_MeshElement*)backElemItr->next();
8805 if ( curElem && theElems.find(curElem) == theElems.end() &&
8806 isInside( curElem, bsc3d, aTol ) )
8807 anAffected.insert( curElem );
8811 return DoubleNodes( theElems, theNodesNot, anAffected );
8815 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
8816 * The created 2D mesh elements based on nodes of free faces of boundary volumes
8817 * \return TRUE if operation has been completed successfully, FALSE otherwise
8820 bool SMESH_MeshEditor::Make2DMeshFrom3D()
8822 // iterates on volume elements and detect all free faces on them
8823 SMESHDS_Mesh* aMesh = GetMeshDS();
8827 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
8830 const SMDS_MeshVolume* volume = vIt->next();
8831 SMDS_VolumeTool vTool( volume );
8832 bool isPoly = volume->IsPoly();
8833 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
8835 if (!vTool.IsFreeFace(iface))
8837 vector<const SMDS_MeshNode *> nodes;
8838 int nbFaceNodes = vTool.NbFaceNodes(iface);
8839 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
8840 if (vTool.IsFaceExternal(iface))
8841 for (int inode = 0; inode < nbFaceNodes; inode++)
8842 nodes.push_back(faceNodes[inode]);
8844 for (int inode = nbFaceNodes - 1; inode >= 0; inode--)
8845 nodes.push_back(faceNodes[inode]);
8847 // add new face based on volume nodes
8848 if (aMesh->FindFace( nodes ) )
8849 continue; // face already exsist
8850 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );