1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
28 #include "SMESH_MeshEditor.hxx"
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_MeshGroup.hxx"
36 #include "SMDS_LinearEdge.hxx"
37 #include "SMDS_Downward.hxx"
38 #include "SMDS_SetIterator.hxx"
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
50 #include <Basics_OCCTVersion.hxx>
52 #include "utilities.h"
54 #include <BRepAdaptor_Surface.hxx>
55 #include <BRepBuilderAPI_MakeEdge.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
100 #include <Standard_Failure.hxx>
101 #include <Standard_ErrorHandler.hxx>
103 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
106 using namespace SMESH::Controls;
108 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
109 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
111 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
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 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
136 SMDS_MeshElement* e = 0;
137 int nbnode = node.size();
138 SMESHDS_Mesh* mesh = GetMeshDS();
143 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
144 else e = mesh->AddFace (node[0], node[1], node[2] );
146 else if (nbnode == 4) {
147 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
148 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
150 else if (nbnode == 6) {
151 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
152 node[4], node[5], ID);
153 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
156 else if (nbnode == 8) {
157 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
158 node[4], node[5], node[6], node[7], ID);
159 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
160 node[4], node[5], node[6], node[7] );
162 else if (nbnode == 9) {
163 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
164 node[4], node[5], node[6], node[7], node[8], ID);
165 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
166 node[4], node[5], node[6], node[7], node[8] );
169 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
170 else e = mesh->AddPolygonalFace (node );
177 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
178 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
180 else if (nbnode == 5) {
181 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
186 else if (nbnode == 6) {
187 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
188 node[4], node[5], ID);
189 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
192 else if (nbnode == 8) {
193 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
194 node[4], node[5], node[6], node[7], ID);
195 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
196 node[4], node[5], node[6], node[7] );
198 else if (nbnode == 10) {
199 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
200 node[4], node[5], node[6], node[7],
201 node[8], node[9], ID);
202 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
203 node[4], node[5], node[6], node[7],
206 else if (nbnode == 12) {
207 if ( ID >= 1 ) 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], ID);
210 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
211 node[4], node[5], node[6], node[7],
212 node[8], node[9], node[10], node[11] );
214 else if (nbnode == 13) {
215 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
216 node[4], node[5], node[6], node[7],
217 node[8], node[9], node[10],node[11],
219 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
220 node[4], node[5], node[6], node[7],
221 node[8], node[9], node[10],node[11],
224 else if (nbnode == 15) {
225 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
226 node[4], node[5], node[6], node[7],
227 node[8], node[9], node[10],node[11],
228 node[12],node[13],node[14],ID);
229 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
230 node[4], node[5], node[6], node[7],
231 node[8], node[9], node[10],node[11],
232 node[12],node[13],node[14] );
234 else if (nbnode == 20) {
235 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
236 node[4], node[5], node[6], node[7],
237 node[8], node[9], node[10],node[11],
238 node[12],node[13],node[14],node[15],
239 node[16],node[17],node[18],node[19],ID);
240 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
241 node[4], node[5], node[6], node[7],
242 node[8], node[9], node[10],node[11],
243 node[12],node[13],node[14],node[15],
244 node[16],node[17],node[18],node[19] );
246 else if (nbnode == 27) {
247 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
248 node[4], node[5], node[6], node[7],
249 node[8], node[9], node[10],node[11],
250 node[12],node[13],node[14],node[15],
251 node[16],node[17],node[18],node[19],
252 node[20],node[21],node[22],node[23],
253 node[24],node[25],node[26], ID);
254 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
255 node[4], node[5], node[6], node[7],
256 node[8], node[9], node[10],node[11],
257 node[12],node[13],node[14],node[15],
258 node[16],node[17],node[18],node[19],
259 node[20],node[21],node[22],node[23],
260 node[24],node[25],node[26] );
267 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
268 else e = mesh->AddEdge (node[0], node[1] );
270 else if ( nbnode == 3 ) {
271 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
272 else e = mesh->AddEdge (node[0], node[1], node[2] );
276 case SMDSAbs_0DElement:
278 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
279 else e = mesh->Add0DElement (node[0] );
284 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
285 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
290 if ( e ) myLastCreatedElems.Append( e );
294 //=======================================================================
298 //=======================================================================
300 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
301 const SMDSAbs_ElementType type,
305 vector<const SMDS_MeshNode*> nodes;
306 nodes.reserve( nodeIDs.size() );
307 vector<int>::const_iterator id = nodeIDs.begin();
308 while ( id != nodeIDs.end() ) {
309 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
310 nodes.push_back( node );
314 return AddElement( nodes, type, isPoly, ID );
317 //=======================================================================
319 //purpose : Remove a node or an element.
320 // Modify a compute state of sub-meshes which become empty
321 //=======================================================================
323 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
326 myLastCreatedElems.Clear();
327 myLastCreatedNodes.Clear();
329 SMESHDS_Mesh* aMesh = GetMeshDS();
330 set< SMESH_subMesh *> smmap;
333 list<int>::const_iterator it = theIDs.begin();
334 for ( ; it != theIDs.end(); it++ ) {
335 const SMDS_MeshElement * elem;
337 elem = aMesh->FindNode( *it );
339 elem = aMesh->FindElement( *it );
343 // Notify VERTEX sub-meshes about modification
345 const SMDS_MeshNode* node = cast2Node( elem );
346 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
347 if ( int aShapeID = node->getshapeId() )
348 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
351 // Find sub-meshes to notify about modification
352 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
353 // while ( nodeIt->more() ) {
354 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
355 // const SMDS_PositionPtr& aPosition = node->GetPosition();
356 // if ( aPosition.get() ) {
357 // if ( int aShapeID = aPosition->GetShapeId() ) {
358 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
359 // smmap.insert( sm );
366 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
368 aMesh->RemoveElement( elem );
372 // Notify sub-meshes about modification
373 if ( !smmap.empty() ) {
374 set< SMESH_subMesh *>::iterator smIt;
375 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
376 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
379 // // Check if the whole mesh becomes empty
380 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
381 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
386 //=======================================================================
387 //function : FindShape
388 //purpose : Return an index of the shape theElem is on
389 // or zero if a shape not found
390 //=======================================================================
392 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
394 myLastCreatedElems.Clear();
395 myLastCreatedNodes.Clear();
397 SMESHDS_Mesh * aMesh = GetMeshDS();
398 if ( aMesh->ShapeToMesh().IsNull() )
401 int aShapeID = theElem->getshapeId();
405 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
406 if ( sm->Contains( theElem ))
409 if ( theElem->GetType() == SMDSAbs_Node ) {
410 MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
413 MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
416 TopoDS_Shape aShape; // the shape a node of theElem is on
417 if ( theElem->GetType() != SMDSAbs_Node )
419 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
420 while ( nodeIt->more() ) {
421 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
422 if ((aShapeID = node->getshapeId()) > 0) {
423 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
424 if ( sm->Contains( theElem ))
426 if ( aShape.IsNull() )
427 aShape = aMesh->IndexToShape( aShapeID );
433 // None of nodes is on a proper shape,
434 // find the shape among ancestors of aShape on which a node is
435 if ( !aShape.IsNull() ) {
436 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
437 for ( ; ancIt.More(); ancIt.Next() ) {
438 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
439 if ( sm && sm->Contains( theElem ))
440 return aMesh->ShapeToIndex( ancIt.Value() );
445 const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
446 map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
447 for ( ; id_sm != id2sm.end(); ++id_sm )
448 if ( id_sm->second->Contains( theElem ))
452 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
456 //=======================================================================
457 //function : IsMedium
459 //=======================================================================
461 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
462 const SMDSAbs_ElementType typeToCheck)
464 bool isMedium = false;
465 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
466 while (it->more() && !isMedium ) {
467 const SMDS_MeshElement* elem = it->next();
468 isMedium = elem->IsMediumNode(node);
473 //=======================================================================
474 //function : ShiftNodesQuadTria
476 // Shift nodes in the array corresponded to quadratic triangle
477 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
478 //=======================================================================
479 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
481 const SMDS_MeshNode* nd1 = aNodes[0];
482 aNodes[0] = aNodes[1];
483 aNodes[1] = aNodes[2];
485 const SMDS_MeshNode* nd2 = aNodes[3];
486 aNodes[3] = aNodes[4];
487 aNodes[4] = aNodes[5];
491 //=======================================================================
492 //function : edgeConnectivity
494 // return number of the edges connected with the theNode.
495 // if theEdges has connections with the other type of the
496 // elements, return -1
497 //=======================================================================
498 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
500 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
502 while(elemIt->more()) {
510 //=======================================================================
511 //function : GetNodesFromTwoTria
513 // Shift nodes in the array corresponded to quadratic triangle
514 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
515 //=======================================================================
516 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
517 const SMDS_MeshElement * theTria2,
518 const SMDS_MeshNode* N1[],
519 const SMDS_MeshNode* N2[])
521 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
524 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
527 if(it->more()) return false;
528 it = theTria2->nodesIterator();
531 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
534 if(it->more()) return false;
536 int sames[3] = {-1,-1,-1};
548 if(nbsames!=2) return false;
550 ShiftNodesQuadTria(N1);
552 ShiftNodesQuadTria(N1);
555 i = sames[0] + sames[1] + sames[2];
557 ShiftNodesQuadTria(N2);
559 // now we receive following N1 and N2 (using numeration as above image)
560 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
561 // i.e. first nodes from both arrays determ new diagonal
565 //=======================================================================
566 //function : InverseDiag
567 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
568 // but having other common link.
569 // Return False if args are improper
570 //=======================================================================
572 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
573 const SMDS_MeshElement * theTria2 )
575 MESSAGE("InverseDiag");
576 myLastCreatedElems.Clear();
577 myLastCreatedNodes.Clear();
579 if (!theTria1 || !theTria2)
582 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
583 if (!F1) return false;
584 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
585 if (!F2) return false;
586 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
587 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
589 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
590 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
594 // put nodes in array and find out indices of the same ones
595 const SMDS_MeshNode* aNodes [6];
596 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
598 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
599 while ( it->more() ) {
600 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
602 if ( i > 2 ) // theTria2
603 // find same node of theTria1
604 for ( int j = 0; j < 3; j++ )
605 if ( aNodes[ i ] == aNodes[ j ]) {
614 return false; // theTria1 is not a triangle
615 it = theTria2->nodesIterator();
617 if ( i == 6 && it->more() )
618 return false; // theTria2 is not a triangle
621 // find indices of 1,2 and of A,B in theTria1
622 int iA = 0, iB = 0, i1 = 0, i2 = 0;
623 for ( i = 0; i < 6; i++ ) {
624 if ( sameInd [ i ] == 0 ) {
633 // nodes 1 and 2 should not be the same
634 if ( aNodes[ i1 ] == aNodes[ i2 ] )
638 aNodes[ iA ] = aNodes[ i2 ];
640 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
642 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
643 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
647 } // end if(F1 && F2)
649 // check case of quadratic faces
650 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
652 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
656 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
657 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
665 const SMDS_MeshNode* N1 [6];
666 const SMDS_MeshNode* N2 [6];
667 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
669 // now we receive following N1 and N2 (using numeration as above image)
670 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
671 // i.e. first nodes from both arrays determ new diagonal
673 const SMDS_MeshNode* N1new [6];
674 const SMDS_MeshNode* N2new [6];
687 // replaces nodes in faces
688 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
689 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
694 //=======================================================================
695 //function : findTriangles
696 //purpose : find triangles sharing theNode1-theNode2 link
697 //=======================================================================
699 static bool findTriangles(const SMDS_MeshNode * theNode1,
700 const SMDS_MeshNode * theNode2,
701 const SMDS_MeshElement*& theTria1,
702 const SMDS_MeshElement*& theTria2)
704 if ( !theNode1 || !theNode2 ) return false;
706 theTria1 = theTria2 = 0;
708 set< const SMDS_MeshElement* > emap;
709 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
711 const SMDS_MeshElement* elem = it->next();
712 if ( elem->NbNodes() == 3 )
715 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
717 const SMDS_MeshElement* elem = it->next();
718 if ( emap.find( elem ) != emap.end() ) {
720 // theTria1 must be element with minimum ID
721 if( theTria1->GetID() < elem->GetID() ) {
735 return ( theTria1 && theTria2 );
738 //=======================================================================
739 //function : InverseDiag
740 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
741 // with ones built on the same 4 nodes but having other common link.
742 // Return false if proper faces not found
743 //=======================================================================
745 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
746 const SMDS_MeshNode * theNode2)
748 myLastCreatedElems.Clear();
749 myLastCreatedNodes.Clear();
751 MESSAGE( "::InverseDiag()" );
753 const SMDS_MeshElement *tr1, *tr2;
754 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
757 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
758 if (!F1) return false;
759 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
760 if (!F2) return false;
761 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
762 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
764 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
765 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
769 // put nodes in array
770 // and find indices of 1,2 and of A in tr1 and of B in tr2
771 int i, iA1 = 0, i1 = 0;
772 const SMDS_MeshNode* aNodes1 [3];
773 SMDS_ElemIteratorPtr it;
774 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
775 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
776 if ( aNodes1[ i ] == theNode1 )
777 iA1 = i; // node A in tr1
778 else if ( aNodes1[ i ] != theNode2 )
782 const SMDS_MeshNode* aNodes2 [3];
783 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
784 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
785 if ( aNodes2[ i ] == theNode2 )
786 iB2 = i; // node B in tr2
787 else if ( aNodes2[ i ] != theNode1 )
791 // nodes 1 and 2 should not be the same
792 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
796 aNodes1[ iA1 ] = aNodes2[ i2 ];
798 aNodes2[ iB2 ] = aNodes1[ i1 ];
800 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
801 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
806 // check case of quadratic faces
807 return InverseDiag(tr1,tr2);
810 //=======================================================================
811 //function : getQuadrangleNodes
812 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
813 // fusion of triangles tr1 and tr2 having shared link on
814 // theNode1 and theNode2
815 //=======================================================================
817 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
818 const SMDS_MeshNode * theNode1,
819 const SMDS_MeshNode * theNode2,
820 const SMDS_MeshElement * tr1,
821 const SMDS_MeshElement * tr2 )
823 if( tr1->NbNodes() != tr2->NbNodes() )
825 // find the 4-th node to insert into tr1
826 const SMDS_MeshNode* n4 = 0;
827 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
829 while ( !n4 && i<3 ) {
830 const SMDS_MeshNode * n = cast2Node( it->next() );
832 bool isDiag = ( n == theNode1 || n == theNode2 );
836 // Make an array of nodes to be in a quadrangle
837 int iNode = 0, iFirstDiag = -1;
838 it = tr1->nodesIterator();
841 const SMDS_MeshNode * n = cast2Node( it->next() );
843 bool isDiag = ( n == theNode1 || n == theNode2 );
845 if ( iFirstDiag < 0 )
847 else if ( iNode - iFirstDiag == 1 )
848 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
850 else if ( n == n4 ) {
851 return false; // tr1 and tr2 should not have all the same nodes
853 theQuadNodes[ iNode++ ] = n;
855 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
856 theQuadNodes[ iNode ] = n4;
861 //=======================================================================
862 //function : DeleteDiag
863 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
864 // with a quadrangle built on the same 4 nodes.
865 // Return false if proper faces not found
866 //=======================================================================
868 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
869 const SMDS_MeshNode * theNode2)
871 myLastCreatedElems.Clear();
872 myLastCreatedNodes.Clear();
874 MESSAGE( "::DeleteDiag()" );
876 const SMDS_MeshElement *tr1, *tr2;
877 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
880 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
881 if (!F1) return false;
882 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
883 if (!F2) return false;
884 SMESHDS_Mesh * aMesh = GetMeshDS();
886 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
887 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
889 const SMDS_MeshNode* aNodes [ 4 ];
890 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
893 const SMDS_MeshElement* newElem = 0;
894 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
895 myLastCreatedElems.Append(newElem);
896 AddToSameGroups( newElem, tr1, aMesh );
897 int aShapeId = tr1->getshapeId();
900 aMesh->SetMeshElementOnShape( newElem, aShapeId );
902 aMesh->RemoveElement( tr1 );
903 aMesh->RemoveElement( tr2 );
908 // check case of quadratic faces
909 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
911 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
915 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
916 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
924 const SMDS_MeshNode* N1 [6];
925 const SMDS_MeshNode* N2 [6];
926 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
928 // now we receive following N1 and N2 (using numeration as above image)
929 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
930 // i.e. first nodes from both arrays determ new diagonal
932 const SMDS_MeshNode* aNodes[8];
942 const SMDS_MeshElement* newElem = 0;
943 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
944 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
945 myLastCreatedElems.Append(newElem);
946 AddToSameGroups( newElem, tr1, aMesh );
947 int aShapeId = tr1->getshapeId();
950 aMesh->SetMeshElementOnShape( newElem, aShapeId );
952 aMesh->RemoveElement( tr1 );
953 aMesh->RemoveElement( tr2 );
955 // remove middle node (9)
956 GetMeshDS()->RemoveNode( N1[4] );
961 //=======================================================================
962 //function : Reorient
963 //purpose : Reverse theElement orientation
964 //=======================================================================
966 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
969 myLastCreatedElems.Clear();
970 myLastCreatedNodes.Clear();
974 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
975 if ( !it || !it->more() )
978 switch ( theElem->GetType() ) {
982 if(!theElem->IsQuadratic()) {
983 int i = theElem->NbNodes();
984 vector<const SMDS_MeshNode*> aNodes( i );
986 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
987 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
990 // quadratic elements
991 if(theElem->GetType()==SMDSAbs_Edge) {
992 vector<const SMDS_MeshNode*> aNodes(3);
993 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
994 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
995 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
996 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
999 int nbn = theElem->NbNodes();
1000 vector<const SMDS_MeshNode*> aNodes(nbn);
1001 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1003 for(; i<nbn/2; i++) {
1004 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1006 for(i=0; i<nbn/2; i++) {
1007 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1009 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1013 case SMDSAbs_Volume: {
1014 if (theElem->IsPoly()) {
1015 // TODO reorient vtk polyhedron
1016 MESSAGE("reorient vtk polyhedron ?");
1017 const SMDS_VtkVolume* aPolyedre =
1018 dynamic_cast<const SMDS_VtkVolume*>( theElem );
1020 MESSAGE("Warning: bad volumic element");
1024 int nbFaces = aPolyedre->NbFaces();
1025 vector<const SMDS_MeshNode *> poly_nodes;
1026 vector<int> quantities (nbFaces);
1028 // reverse each face of the polyedre
1029 for (int iface = 1; iface <= nbFaces; iface++) {
1030 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1031 quantities[iface - 1] = nbFaceNodes;
1033 for (inode = nbFaceNodes; inode >= 1; inode--) {
1034 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1035 poly_nodes.push_back(curNode);
1039 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1043 SMDS_VolumeTool vTool;
1044 if ( !vTool.Set( theElem ))
1047 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1048 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1057 //================================================================================
1059 * \brief Reorient faces.
1060 * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1061 * \param theDirection - desired direction of normal of \a theFace
1062 * \param theFace - one of \a theFaces that sould be orientated according to
1063 * \a theDirection and whose orientation defines orientation of other faces
1064 * \return number of reoriented faces.
1066 //================================================================================
1068 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces,
1069 const gp_Dir& theDirection,
1070 const SMDS_MeshElement * theFace)
1073 if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1075 if ( theFaces.empty() )
1077 SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1078 while ( fIt->more() )
1079 theFaces.insert( theFaces.end(), fIt->next() );
1082 // orient theFace according to theDirection
1084 SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false );
1085 if ( normal * theDirection.XYZ() < 0 )
1086 nbReori += Reorient( theFace );
1088 // Orient other faces
1090 set< const SMDS_MeshElement* > startFaces;
1091 TIDSortedElemSet avoidSet;
1092 set< SMESH_TLink > checkedLinks;
1093 pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1095 if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1096 theFaces.erase( theFace );
1097 startFaces.insert( theFace );
1099 set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1100 while ( startFace != startFaces.end() )
1102 theFace = *startFace;
1103 const int nbNodes = theFace->NbCornerNodes();
1106 avoidSet.insert(theFace);
1108 NLink link( theFace->GetNode( 0 ), 0 );
1109 for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1111 link.second = theFace->GetNode(( i+1 ) % nbNodes );
1112 linkIt_isNew = checkedLinks.insert( link );
1113 if ( !linkIt_isNew.second )
1115 // link has already been checked and won't be encountered more
1116 // if the group (theFaces) is manifold
1117 checkedLinks.erase( linkIt_isNew.first );
1121 int nodeInd1, nodeInd2;
1122 const SMDS_MeshElement* otherFace = FindFaceInSet( link.first, link.second,
1124 & nodeInd1, & nodeInd2);
1125 if ( otherFace && otherFace != theFace)
1127 // link must be reversed in otherFace if orientation ot otherFace
1128 // is same as that of theFace
1129 if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1131 // cout << "Reorient " << otherFace->GetID() << " near theFace=" <<theFace->GetID()
1132 // << " \tlink( " << link.first->GetID() << " " << link.second->GetID() << endl;
1133 nbReori += Reorient( otherFace );
1135 startFaces.insert( otherFace );
1136 if ( theFaces.size() > 1 ) // leave 1 face to prevent finding not selected faces
1137 theFaces.erase( otherFace );
1140 std::swap( link.first, link.second );
1142 startFaces.erase( startFace );
1143 startFace = startFaces.begin();
1148 //=======================================================================
1149 //function : getBadRate
1151 //=======================================================================
1153 static double getBadRate (const SMDS_MeshElement* theElem,
1154 SMESH::Controls::NumericalFunctorPtr& theCrit)
1156 SMESH::Controls::TSequenceOfXYZ P;
1157 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1159 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1160 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1163 //=======================================================================
1164 //function : QuadToTri
1165 //purpose : Cut quadrangles into triangles.
1166 // theCrit is used to select a diagonal to cut
1167 //=======================================================================
1169 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1170 SMESH::Controls::NumericalFunctorPtr theCrit)
1172 myLastCreatedElems.Clear();
1173 myLastCreatedNodes.Clear();
1175 MESSAGE( "::QuadToTri()" );
1177 if ( !theCrit.get() )
1180 SMESHDS_Mesh * aMesh = GetMeshDS();
1182 Handle(Geom_Surface) surface;
1183 SMESH_MesherHelper helper( *GetMesh() );
1185 TIDSortedElemSet::iterator itElem;
1186 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1187 const SMDS_MeshElement* elem = *itElem;
1188 if ( !elem || elem->GetType() != SMDSAbs_Face )
1190 if ( elem->NbCornerNodes() != 4 )
1193 // retrieve element nodes
1194 vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1196 // compare two sets of possible triangles
1197 double aBadRate1, aBadRate2; // to what extent a set is bad
1198 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1199 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1200 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1202 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1203 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1204 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1206 int aShapeId = FindShape( elem );
1207 const SMDS_MeshElement* newElem1 = 0;
1208 const SMDS_MeshElement* newElem2 = 0;
1210 if( !elem->IsQuadratic() ) {
1212 // split liner quadrangle
1214 if ( aBadRate1 <= aBadRate2 ) {
1215 // tr1 + tr2 is better
1216 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1217 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1220 // tr3 + tr4 is better
1221 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1222 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1227 // split quadratic quadrangle
1229 // get surface elem is on
1230 if ( aShapeId != helper.GetSubShapeID() ) {
1234 shape = aMesh->IndexToShape( aShapeId );
1235 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1236 TopoDS_Face face = TopoDS::Face( shape );
1237 surface = BRep_Tool::Surface( face );
1238 if ( !surface.IsNull() )
1239 helper.SetSubShape( shape );
1242 // find middle point for (0,1,2,3)
1243 // and create a node in this point;
1244 const SMDS_MeshNode* newN = 0;
1245 if ( aNodes.size() == 9 )
1247 // SMDSEntity_BiQuad_Quadrangle
1248 newN = aNodes.back();
1253 if ( surface.IsNull() )
1255 for ( int i = 0; i < 4; i++ )
1256 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1261 const SMDS_MeshNode* inFaceNode = 0;
1262 if ( helper.GetNodeUVneedInFaceNode() )
1263 for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1264 if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1265 inFaceNode = aNodes[ i ];
1267 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1269 for ( int i = 0; i < 4; i++ )
1270 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1272 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1274 newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1275 myLastCreatedNodes.Append(newN);
1277 // create a new element
1278 if ( aBadRate1 <= aBadRate2 ) {
1279 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1280 aNodes[6], aNodes[7], newN );
1281 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1282 newN, aNodes[4], aNodes[5] );
1285 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1286 aNodes[7], aNodes[4], newN );
1287 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1288 newN, aNodes[5], aNodes[6] );
1292 // care of a new element
1294 myLastCreatedElems.Append(newElem1);
1295 myLastCreatedElems.Append(newElem2);
1296 AddToSameGroups( newElem1, elem, aMesh );
1297 AddToSameGroups( newElem2, elem, aMesh );
1299 // put a new triangle on the same shape
1302 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1303 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1305 aMesh->RemoveElement( elem );
1310 //=======================================================================
1311 //function : BestSplit
1312 //purpose : Find better diagonal for cutting.
1313 //=======================================================================
1315 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1316 SMESH::Controls::NumericalFunctorPtr theCrit)
1318 myLastCreatedElems.Clear();
1319 myLastCreatedNodes.Clear();
1324 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1327 if( theQuad->NbNodes()==4 ||
1328 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1330 // retrieve element nodes
1331 const SMDS_MeshNode* aNodes [4];
1332 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1334 //while (itN->more())
1336 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1338 // compare two sets of possible triangles
1339 double aBadRate1, aBadRate2; // to what extent a set is bad
1340 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1341 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1342 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1344 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1345 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1346 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1348 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1349 return 1; // diagonal 1-3
1351 return 2; // diagonal 2-4
1358 // Methods of splitting volumes into tetra
1360 const int theHexTo5_1[5*4+1] =
1362 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1364 const int theHexTo5_2[5*4+1] =
1366 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1368 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1370 const int theHexTo6_1[6*4+1] =
1372 1, 5, 6, 0, 0, 1, 2, 6, 0, 4, 5, 6, 0, 4, 6, 7, 0, 2, 3, 6, 0, 3, 7, 6, -1
1374 const int theHexTo6_2[6*4+1] =
1376 2, 6, 7, 1, 1, 2, 3, 7, 1, 5, 6, 7, 1, 5, 7, 4, 1, 3, 0, 7, 1, 0, 4, 7, -1
1378 const int theHexTo6_3[6*4+1] =
1380 3, 7, 4, 2, 2, 3, 0, 4, 2, 6, 7, 4, 2, 6, 4, 5, 2, 0, 1, 4, 2, 1, 5, 4, -1
1382 const int theHexTo6_4[6*4+1] =
1384 0, 4, 5, 3, 3, 0, 1, 5, 3, 7, 4, 5, 3, 7, 5, 6, 3, 1, 2, 5, 3, 2, 6, 5, -1
1386 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1388 const int thePyraTo2_1[2*4+1] =
1390 0, 1, 2, 4, 0, 2, 3, 4, -1
1392 const int thePyraTo2_2[2*4+1] =
1394 1, 2, 3, 4, 1, 3, 0, 4, -1
1396 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1398 const int thePentaTo3_1[3*4+1] =
1400 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1402 const int thePentaTo3_2[3*4+1] =
1404 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1406 const int thePentaTo3_3[3*4+1] =
1408 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1410 const int thePentaTo3_4[3*4+1] =
1412 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1414 const int thePentaTo3_5[3*4+1] =
1416 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1418 const int thePentaTo3_6[3*4+1] =
1420 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1422 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1423 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1425 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1428 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1429 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1430 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1435 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1436 bool _baryNode; //!< additional node is to be created at cell barycenter
1437 bool _ownConn; //!< to delete _connectivity in destructor
1438 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1440 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1441 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1442 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1443 bool hasFacet( const TTriangleFacet& facet ) const
1445 const int* tetConn = _connectivity;
1446 for ( ; tetConn[0] >= 0; tetConn += 4 )
1447 if (( facet.contains( tetConn[0] ) +
1448 facet.contains( tetConn[1] ) +
1449 facet.contains( tetConn[2] ) +
1450 facet.contains( tetConn[3] )) == 3 )
1456 //=======================================================================
1458 * \brief return TSplitMethod for the given element
1460 //=======================================================================
1462 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1464 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1466 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1467 // an edge and a face barycenter; tertaherdons are based on triangles and
1468 // a volume barycenter
1469 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1471 // Find out how adjacent volumes are split
1473 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1474 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1475 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1477 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1478 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1479 if ( nbNodes < 4 ) continue;
1481 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1482 const int* nInd = vol.GetFaceNodesIndices( iF );
1485 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1486 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1487 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1488 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1492 int iCom = 0; // common node of triangle faces to split into
1493 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1495 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1496 nInd[ iQ * ( (iCom+1)%nbNodes )],
1497 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1498 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1499 nInd[ iQ * ( (iCom+2)%nbNodes )],
1500 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1501 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1503 triaSplits.push_back( t012 );
1504 triaSplits.push_back( t023 );
1509 if ( !triaSplits.empty() )
1510 hasAdjacentSplits = true;
1513 // Among variants of split method select one compliant with adjacent volumes
1515 TSplitMethod method;
1516 if ( !vol.Element()->IsPoly() && !is24TetMode )
1518 int nbVariants = 2, nbTet = 0;
1519 const int** connVariants = 0;
1520 switch ( vol.Element()->GetEntityType() )
1522 case SMDSEntity_Hexa:
1523 case SMDSEntity_Quad_Hexa:
1524 case SMDSEntity_TriQuad_Hexa:
1525 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1526 connVariants = theHexTo5, nbTet = 5;
1528 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1530 case SMDSEntity_Pyramid:
1531 case SMDSEntity_Quad_Pyramid:
1532 connVariants = thePyraTo2; nbTet = 2;
1534 case SMDSEntity_Penta:
1535 case SMDSEntity_Quad_Penta:
1536 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1541 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1543 // check method compliancy with adjacent tetras,
1544 // all found splits must be among facets of tetras described by this method
1545 method = TSplitMethod( nbTet, connVariants[variant] );
1546 if ( hasAdjacentSplits && method._nbTetra > 0 )
1548 bool facetCreated = true;
1549 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1551 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1552 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1553 facetCreated = method.hasFacet( *facet );
1555 if ( !facetCreated )
1556 method = TSplitMethod(0); // incompatible method
1560 if ( method._nbTetra < 1 )
1562 // No standard method is applicable, use a generic solution:
1563 // each facet of a volume is split into triangles and
1564 // each of triangles and a volume barycenter form a tetrahedron.
1566 const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1568 int* connectivity = new int[ maxTetConnSize + 1 ];
1569 method._connectivity = connectivity;
1570 method._ownConn = true;
1571 method._baryNode = !isHex27; // to create central node or not
1574 int baryCenInd = vol.NbNodes() - int( isHex27 );
1575 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1577 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1578 const int* nInd = vol.GetFaceNodesIndices( iF );
1579 // find common node of triangle facets of tetra to create
1580 int iCommon = 0; // index in linear numeration
1581 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1582 if ( !triaSplits.empty() )
1585 const TTriangleFacet* facet = &triaSplits.front();
1586 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1587 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1588 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1591 else if ( nbNodes > 3 && !is24TetMode )
1593 // find the best method of splitting into triangles by aspect ratio
1594 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1595 map< double, int > badness2iCommon;
1596 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1597 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1598 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1601 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1603 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1604 nodes[ iQ*((iLast-1)%nbNodes)],
1605 nodes[ iQ*((iLast )%nbNodes)]);
1606 badness += getBadRate( &tria, aspectRatio );
1608 badness2iCommon.insert( make_pair( badness, iCommon ));
1610 // use iCommon with lowest badness
1611 iCommon = badness2iCommon.begin()->second;
1613 if ( iCommon >= nbNodes )
1614 iCommon = 0; // something wrong
1616 // fill connectivity of tetrahedra based on a current face
1617 int nbTet = nbNodes - 2;
1618 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1623 faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1624 method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1628 method._faceBaryNode[ iF ] = 0;
1629 faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1632 for ( int i = 0; i < nbTet; ++i )
1634 int i1 = i, i2 = (i+1) % nbNodes;
1635 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1636 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1637 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1638 connectivity[ connSize++ ] = faceBaryCenInd;
1639 connectivity[ connSize++ ] = baryCenInd;
1644 for ( int i = 0; i < nbTet; ++i )
1646 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1647 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1648 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1649 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1650 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1651 connectivity[ connSize++ ] = baryCenInd;
1654 method._nbTetra += nbTet;
1656 } // loop on volume faces
1658 connectivity[ connSize++ ] = -1;
1660 } // end of generic solution
1664 //================================================================================
1666 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1668 //================================================================================
1670 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1672 // find the tetrahedron including the three nodes of facet
1673 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1674 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1675 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1676 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1677 while ( volIt1->more() )
1679 const SMDS_MeshElement* v = volIt1->next();
1680 SMDSAbs_EntityType type = v->GetEntityType();
1681 if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1683 if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1684 continue; // medium node not allowed
1685 const int ind2 = v->GetNodeIndex( n2 );
1686 if ( ind2 < 0 || 3 < ind2 )
1688 const int ind3 = v->GetNodeIndex( n3 );
1689 if ( ind3 < 0 || 3 < ind3 )
1696 //=======================================================================
1698 * \brief A key of a face of volume
1700 //=======================================================================
1702 struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1704 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1706 TIDSortedNodeSet sortedNodes;
1707 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1708 int nbNodes = vol.NbFaceNodes( iF );
1709 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1710 for ( int i = 0; i < nbNodes; i += iQ )
1711 sortedNodes.insert( fNodes[i] );
1712 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1713 first.first = (*(n++))->GetID();
1714 first.second = (*(n++))->GetID();
1715 second.first = (*(n++))->GetID();
1716 second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1721 //=======================================================================
1722 //function : SplitVolumesIntoTetra
1723 //purpose : Split volume elements into tetrahedra.
1724 //=======================================================================
1726 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1727 const int theMethodFlags)
1729 // std-like iterator on coordinates of nodes of mesh element
1730 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1731 NXyzIterator xyzEnd;
1733 SMDS_VolumeTool volTool;
1734 SMESH_MesherHelper helper( *GetMesh());
1736 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1737 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1739 SMESH_SequenceOfElemPtr newNodes, newElems;
1741 // map face of volume to it's baricenrtic node
1742 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1745 TIDSortedElemSet::const_iterator elem = theElems.begin();
1746 for ( ; elem != theElems.end(); ++elem )
1748 if ( (*elem)->GetType() != SMDSAbs_Volume )
1750 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1751 if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1754 if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1756 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1757 if ( splitMethod._nbTetra < 1 ) continue;
1759 // find submesh to add new tetras to
1760 if ( !subMesh || !subMesh->Contains( *elem ))
1762 int shapeID = FindShape( *elem );
1763 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1764 subMesh = GetMeshDS()->MeshElements( shapeID );
1767 if ( (*elem)->IsQuadratic() )
1770 // add quadratic links to the helper
1771 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1773 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1774 int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1775 for ( int iN = 0; iN < nbN; iN += iQ )
1776 helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1778 helper.SetIsQuadratic( true );
1783 helper.SetIsQuadratic( false );
1785 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1786 helper.SetElementsOnShape( true );
1787 if ( splitMethod._baryNode )
1789 // make a node at barycenter
1790 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1791 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1792 nodes.push_back( gcNode );
1793 newNodes.Append( gcNode );
1795 if ( !splitMethod._faceBaryNode.empty() )
1797 // make or find baricentric nodes of faces
1798 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1799 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1801 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1802 volFace2BaryNode.insert
1803 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1806 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1807 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1809 nodes.push_back( iF_n->second = f_n->second );
1814 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1815 const int* tetConn = splitMethod._connectivity;
1816 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1817 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1818 nodes[ tetConn[1] ],
1819 nodes[ tetConn[2] ],
1820 nodes[ tetConn[3] ]));
1822 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1824 // Split faces on sides of the split volume
1826 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1827 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1829 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1830 if ( nbNodes < 4 ) continue;
1832 // find an existing face
1833 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1834 volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1835 while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1836 /*noMedium=*/false))
1839 helper.SetElementsOnShape( false );
1840 vector< const SMDS_MeshElement* > triangles;
1842 // find submesh to add new triangles in
1843 if ( !fSubMesh || !fSubMesh->Contains( face ))
1845 int shapeID = FindShape( face );
1846 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1848 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1849 if ( iF_n != splitMethod._faceBaryNode.end() )
1851 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1853 const SMDS_MeshNode* n1 = fNodes[iN];
1854 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1855 const SMDS_MeshNode *n3 = iF_n->second;
1856 if ( !volTool.IsFaceExternal( iF ))
1858 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1860 if ( fSubMesh && n3->getshapeId() < 1 )
1861 fSubMesh->AddNode( n3 );
1866 // among possible triangles create ones discribed by split method
1867 const int* nInd = volTool.GetFaceNodesIndices( iF );
1868 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1869 int iCom = 0; // common node of triangle faces to split into
1870 list< TTriangleFacet > facets;
1871 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1873 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1874 nInd[ iQ * ( (iCom+1)%nbNodes )],
1875 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1876 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1877 nInd[ iQ * ( (iCom+2)%nbNodes )],
1878 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1879 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1881 facets.push_back( t012 );
1882 facets.push_back( t023 );
1883 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1884 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1885 nInd[ iQ * ((iLast-1)%nbNodes )],
1886 nInd[ iQ * ((iLast )%nbNodes )]));
1890 list< TTriangleFacet >::iterator facet = facets.begin();
1891 for ( ; facet != facets.end(); ++facet )
1893 if ( !volTool.IsFaceExternal( iF ))
1894 swap( facet->_n2, facet->_n3 );
1895 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1896 volNodes[ facet->_n2 ],
1897 volNodes[ facet->_n3 ]));
1900 for ( int i = 0; i < triangles.size(); ++i )
1902 if ( !triangles[i] ) continue;
1904 fSubMesh->AddElement( triangles[i]);
1905 newElems.Append( triangles[i] );
1907 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1908 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1911 } // loop on volume faces to split them into triangles
1913 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1915 if ( geomType == SMDSEntity_TriQuad_Hexa )
1917 // remove medium nodes that could become free
1918 for ( int i = 20; i < volTool.NbNodes(); ++i )
1919 if ( volNodes[i]->NbInverseElements() == 0 )
1920 GetMeshDS()->RemoveNode( volNodes[i] );
1922 } // loop on volumes to split
1924 myLastCreatedNodes = newNodes;
1925 myLastCreatedElems = newElems;
1928 //=======================================================================
1929 //function : AddToSameGroups
1930 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1931 //=======================================================================
1933 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1934 const SMDS_MeshElement* elemInGroups,
1935 SMESHDS_Mesh * aMesh)
1937 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1938 if (!groups.empty()) {
1939 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1940 for ( ; grIt != groups.end(); grIt++ ) {
1941 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1942 if ( group && group->Contains( elemInGroups ))
1943 group->SMDSGroup().Add( elemToAdd );
1949 //=======================================================================
1950 //function : RemoveElemFromGroups
1951 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1952 //=======================================================================
1953 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1954 SMESHDS_Mesh * aMesh)
1956 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1957 if (!groups.empty())
1959 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1960 for (; GrIt != groups.end(); GrIt++)
1962 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1963 if (!grp || grp->IsEmpty()) continue;
1964 grp->SMDSGroup().Remove(removeelem);
1969 //================================================================================
1971 * \brief Replace elemToRm by elemToAdd in the all groups
1973 //================================================================================
1975 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1976 const SMDS_MeshElement* elemToAdd,
1977 SMESHDS_Mesh * aMesh)
1979 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1980 if (!groups.empty()) {
1981 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1982 for ( ; grIt != groups.end(); grIt++ ) {
1983 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1984 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1985 group->SMDSGroup().Add( elemToAdd );
1990 //================================================================================
1992 * \brief Replace elemToRm by elemToAdd in the all groups
1994 //================================================================================
1996 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1997 const vector<const SMDS_MeshElement*>& elemToAdd,
1998 SMESHDS_Mesh * aMesh)
2000 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2001 if (!groups.empty())
2003 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2004 for ( ; grIt != groups.end(); grIt++ ) {
2005 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2006 if ( group && group->SMDSGroup().Remove( elemToRm ) )
2007 for ( int i = 0; i < elemToAdd.size(); ++i )
2008 group->SMDSGroup().Add( elemToAdd[ i ] );
2013 //=======================================================================
2014 //function : QuadToTri
2015 //purpose : Cut quadrangles into triangles.
2016 // theCrit is used to select a diagonal to cut
2017 //=======================================================================
2019 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2020 const bool the13Diag)
2022 myLastCreatedElems.Clear();
2023 myLastCreatedNodes.Clear();
2025 MESSAGE( "::QuadToTri()" );
2027 SMESHDS_Mesh * aMesh = GetMeshDS();
2029 Handle(Geom_Surface) surface;
2030 SMESH_MesherHelper helper( *GetMesh() );
2032 TIDSortedElemSet::iterator itElem;
2033 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2034 const SMDS_MeshElement* elem = *itElem;
2035 if ( !elem || elem->GetType() != SMDSAbs_Face )
2037 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2038 if(!isquad) continue;
2040 if(elem->NbNodes()==4) {
2041 // retrieve element nodes
2042 const SMDS_MeshNode* aNodes [4];
2043 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2045 while ( itN->more() )
2046 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2048 int aShapeId = FindShape( elem );
2049 const SMDS_MeshElement* newElem1 = 0;
2050 const SMDS_MeshElement* newElem2 = 0;
2052 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2053 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2056 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2057 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2059 myLastCreatedElems.Append(newElem1);
2060 myLastCreatedElems.Append(newElem2);
2061 // put a new triangle on the same shape and add to the same groups
2064 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2065 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2067 AddToSameGroups( newElem1, elem, aMesh );
2068 AddToSameGroups( newElem2, elem, aMesh );
2069 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2070 aMesh->RemoveElement( elem );
2073 // Quadratic quadrangle
2075 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2077 // get surface elem is on
2078 int aShapeId = FindShape( elem );
2079 if ( aShapeId != helper.GetSubShapeID() ) {
2083 shape = aMesh->IndexToShape( aShapeId );
2084 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2085 TopoDS_Face face = TopoDS::Face( shape );
2086 surface = BRep_Tool::Surface( face );
2087 if ( !surface.IsNull() )
2088 helper.SetSubShape( shape );
2092 const SMDS_MeshNode* aNodes [8];
2093 const SMDS_MeshNode* inFaceNode = 0;
2094 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2096 while ( itN->more() ) {
2097 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2098 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2099 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2101 inFaceNode = aNodes[ i-1 ];
2105 // find middle point for (0,1,2,3)
2106 // and create a node in this point;
2108 if ( surface.IsNull() ) {
2110 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2114 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2117 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2119 p = surface->Value( uv.X(), uv.Y() ).XYZ();
2121 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2122 myLastCreatedNodes.Append(newN);
2124 // create a new element
2125 const SMDS_MeshElement* newElem1 = 0;
2126 const SMDS_MeshElement* newElem2 = 0;
2128 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2129 aNodes[6], aNodes[7], newN );
2130 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2131 newN, aNodes[4], aNodes[5] );
2134 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2135 aNodes[7], aNodes[4], newN );
2136 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2137 newN, aNodes[5], aNodes[6] );
2139 myLastCreatedElems.Append(newElem1);
2140 myLastCreatedElems.Append(newElem2);
2141 // put a new triangle on the same shape and add to the same groups
2144 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2145 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2147 AddToSameGroups( newElem1, elem, aMesh );
2148 AddToSameGroups( newElem2, elem, aMesh );
2149 aMesh->RemoveElement( elem );
2156 //=======================================================================
2157 //function : getAngle
2159 //=======================================================================
2161 double getAngle(const SMDS_MeshElement * tr1,
2162 const SMDS_MeshElement * tr2,
2163 const SMDS_MeshNode * n1,
2164 const SMDS_MeshNode * n2)
2166 double angle = 2. * M_PI; // bad angle
2169 SMESH::Controls::TSequenceOfXYZ P1, P2;
2170 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2171 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2174 if(!tr1->IsQuadratic())
2175 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2177 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2178 if ( N1.SquareMagnitude() <= gp::Resolution() )
2180 if(!tr2->IsQuadratic())
2181 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2183 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2184 if ( N2.SquareMagnitude() <= gp::Resolution() )
2187 // find the first diagonal node n1 in the triangles:
2188 // take in account a diagonal link orientation
2189 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2190 for ( int t = 0; t < 2; t++ ) {
2191 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2192 int i = 0, iDiag = -1;
2193 while ( it->more()) {
2194 const SMDS_MeshElement *n = it->next();
2195 if ( n == n1 || n == n2 ) {
2199 if ( i - iDiag == 1 )
2200 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2209 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2212 angle = N1.Angle( N2 );
2217 // =================================================
2218 // class generating a unique ID for a pair of nodes
2219 // and able to return nodes by that ID
2220 // =================================================
2224 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2225 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2228 long GetLinkID (const SMDS_MeshNode * n1,
2229 const SMDS_MeshNode * n2) const
2231 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2234 bool GetNodes (const long theLinkID,
2235 const SMDS_MeshNode* & theNode1,
2236 const SMDS_MeshNode* & theNode2) const
2238 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2239 if ( !theNode1 ) return false;
2240 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2241 if ( !theNode2 ) return false;
2247 const SMESHDS_Mesh* myMesh;
2252 //=======================================================================
2253 //function : TriToQuad
2254 //purpose : Fuse neighbour triangles into quadrangles.
2255 // theCrit is used to select a neighbour to fuse with.
2256 // theMaxAngle is a max angle between element normals at which
2257 // fusion is still performed.
2258 //=======================================================================
2260 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2261 SMESH::Controls::NumericalFunctorPtr theCrit,
2262 const double theMaxAngle)
2264 myLastCreatedElems.Clear();
2265 myLastCreatedNodes.Clear();
2267 MESSAGE( "::TriToQuad()" );
2269 if ( !theCrit.get() )
2272 SMESHDS_Mesh * aMesh = GetMeshDS();
2274 // Prepare data for algo: build
2275 // 1. map of elements with their linkIDs
2276 // 2. map of linkIDs with their elements
2278 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2279 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2280 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2281 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2283 TIDSortedElemSet::iterator itElem;
2284 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2285 const SMDS_MeshElement* elem = *itElem;
2286 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2287 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2288 if(!IsTria) continue;
2290 // retrieve element nodes
2291 const SMDS_MeshNode* aNodes [4];
2292 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2295 aNodes[ i++ ] = cast2Node( itN->next() );
2296 aNodes[ 3 ] = aNodes[ 0 ];
2299 for ( i = 0; i < 3; i++ ) {
2300 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2301 // check if elements sharing a link can be fused
2302 itLE = mapLi_listEl.find( link );
2303 if ( itLE != mapLi_listEl.end() ) {
2304 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2306 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2307 //if ( FindShape( elem ) != FindShape( elem2 ))
2308 // continue; // do not fuse triangles laying on different shapes
2309 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2310 continue; // avoid making badly shaped quads
2311 (*itLE).second.push_back( elem );
2314 mapLi_listEl[ link ].push_back( elem );
2316 mapEl_setLi [ elem ].insert( link );
2319 // Clean the maps from the links shared by a sole element, ie
2320 // links to which only one element is bound in mapLi_listEl
2322 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2323 int nbElems = (*itLE).second.size();
2324 if ( nbElems < 2 ) {
2325 const SMDS_MeshElement* elem = (*itLE).second.front();
2326 SMESH_TLink link = (*itLE).first;
2327 mapEl_setLi[ elem ].erase( link );
2328 if ( mapEl_setLi[ elem ].empty() )
2329 mapEl_setLi.erase( elem );
2333 // Algo: fuse triangles into quadrangles
2335 while ( ! mapEl_setLi.empty() ) {
2336 // Look for the start element:
2337 // the element having the least nb of shared links
2338 const SMDS_MeshElement* startElem = 0;
2340 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2341 int nbLinks = (*itEL).second.size();
2342 if ( nbLinks < minNbLinks ) {
2343 startElem = (*itEL).first;
2344 minNbLinks = nbLinks;
2345 if ( minNbLinks == 1 )
2350 // search elements to fuse starting from startElem or links of elements
2351 // fused earlyer - startLinks
2352 list< SMESH_TLink > startLinks;
2353 while ( startElem || !startLinks.empty() ) {
2354 while ( !startElem && !startLinks.empty() ) {
2355 // Get an element to start, by a link
2356 SMESH_TLink linkId = startLinks.front();
2357 startLinks.pop_front();
2358 itLE = mapLi_listEl.find( linkId );
2359 if ( itLE != mapLi_listEl.end() ) {
2360 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2361 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2362 for ( ; itE != listElem.end() ; itE++ )
2363 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2365 mapLi_listEl.erase( itLE );
2370 // Get candidates to be fused
2371 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2372 const SMESH_TLink *link12, *link13;
2374 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2375 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2376 ASSERT( !setLi.empty() );
2377 set< SMESH_TLink >::iterator itLi;
2378 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2380 const SMESH_TLink & link = (*itLi);
2381 itLE = mapLi_listEl.find( link );
2382 if ( itLE == mapLi_listEl.end() )
2385 const SMDS_MeshElement* elem = (*itLE).second.front();
2387 elem = (*itLE).second.back();
2388 mapLi_listEl.erase( itLE );
2389 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2400 // add other links of elem to list of links to re-start from
2401 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2402 set< SMESH_TLink >::iterator it;
2403 for ( it = links.begin(); it != links.end(); it++ ) {
2404 const SMESH_TLink& link2 = (*it);
2405 if ( link2 != link )
2406 startLinks.push_back( link2 );
2410 // Get nodes of possible quadrangles
2411 const SMDS_MeshNode *n12 [4], *n13 [4];
2412 bool Ok12 = false, Ok13 = false;
2413 const SMDS_MeshNode *linkNode1, *linkNode2;
2415 linkNode1 = link12->first;
2416 linkNode2 = link12->second;
2417 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2421 linkNode1 = link13->first;
2422 linkNode2 = link13->second;
2423 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2427 // Choose a pair to fuse
2428 if ( Ok12 && Ok13 ) {
2429 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2430 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2431 double aBadRate12 = getBadRate( &quad12, theCrit );
2432 double aBadRate13 = getBadRate( &quad13, theCrit );
2433 if ( aBadRate13 < aBadRate12 )
2440 // and remove fused elems and removed links from the maps
2441 mapEl_setLi.erase( tr1 );
2443 mapEl_setLi.erase( tr2 );
2444 mapLi_listEl.erase( *link12 );
2445 if(tr1->NbNodes()==3) {
2446 const SMDS_MeshElement* newElem = 0;
2447 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2448 myLastCreatedElems.Append(newElem);
2449 AddToSameGroups( newElem, tr1, aMesh );
2450 int aShapeId = tr1->getshapeId();
2453 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2455 aMesh->RemoveElement( tr1 );
2456 aMesh->RemoveElement( tr2 );
2459 const SMDS_MeshNode* N1 [6];
2460 const SMDS_MeshNode* N2 [6];
2461 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2462 // now we receive following N1 and N2 (using numeration as above image)
2463 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2464 // i.e. first nodes from both arrays determ new diagonal
2465 const SMDS_MeshNode* aNodes[8];
2474 const SMDS_MeshElement* newElem = 0;
2475 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2476 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2477 myLastCreatedElems.Append(newElem);
2478 AddToSameGroups( newElem, tr1, aMesh );
2479 int aShapeId = tr1->getshapeId();
2482 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2484 aMesh->RemoveElement( tr1 );
2485 aMesh->RemoveElement( tr2 );
2486 // remove middle node (9)
2487 GetMeshDS()->RemoveNode( N1[4] );
2491 mapEl_setLi.erase( tr3 );
2492 mapLi_listEl.erase( *link13 );
2493 if(tr1->NbNodes()==3) {
2494 const SMDS_MeshElement* newElem = 0;
2495 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2496 myLastCreatedElems.Append(newElem);
2497 AddToSameGroups( newElem, tr1, aMesh );
2498 int aShapeId = tr1->getshapeId();
2501 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2503 aMesh->RemoveElement( tr1 );
2504 aMesh->RemoveElement( tr3 );
2507 const SMDS_MeshNode* N1 [6];
2508 const SMDS_MeshNode* N2 [6];
2509 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2510 // now we receive following N1 and N2 (using numeration as above image)
2511 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2512 // i.e. first nodes from both arrays determ new diagonal
2513 const SMDS_MeshNode* aNodes[8];
2522 const SMDS_MeshElement* newElem = 0;
2523 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2524 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2525 myLastCreatedElems.Append(newElem);
2526 AddToSameGroups( newElem, tr1, aMesh );
2527 int aShapeId = tr1->getshapeId();
2530 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2532 aMesh->RemoveElement( tr1 );
2533 aMesh->RemoveElement( tr3 );
2534 // remove middle node (9)
2535 GetMeshDS()->RemoveNode( N1[4] );
2539 // Next element to fuse: the rejected one
2541 startElem = Ok12 ? tr3 : tr2;
2543 } // if ( startElem )
2544 } // while ( startElem || !startLinks.empty() )
2545 } // while ( ! mapEl_setLi.empty() )
2551 /*#define DUMPSO(txt) \
2552 // cout << txt << endl;
2553 //=============================================================================
2557 //=============================================================================
2558 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2562 int tmp = idNodes[ i1 ];
2563 idNodes[ i1 ] = idNodes[ i2 ];
2564 idNodes[ i2 ] = tmp;
2565 gp_Pnt Ptmp = P[ i1 ];
2568 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2571 //=======================================================================
2572 //function : SortQuadNodes
2573 //purpose : Set 4 nodes of a quadrangle face in a good order.
2574 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2576 //=======================================================================
2578 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2583 for ( i = 0; i < 4; i++ ) {
2584 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2586 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2589 gp_Vec V1(P[0], P[1]);
2590 gp_Vec V2(P[0], P[2]);
2591 gp_Vec V3(P[0], P[3]);
2593 gp_Vec Cross1 = V1 ^ V2;
2594 gp_Vec Cross2 = V2 ^ V3;
2597 if (Cross1.Dot(Cross2) < 0)
2602 if (Cross1.Dot(Cross2) < 0)
2606 swap ( i, i + 1, idNodes, P );
2608 // for ( int ii = 0; ii < 4; ii++ ) {
2609 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2610 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2616 //=======================================================================
2617 //function : SortHexaNodes
2618 //purpose : Set 8 nodes of a hexahedron in a good order.
2619 // Return success status
2620 //=======================================================================
2622 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2627 DUMPSO( "INPUT: ========================================");
2628 for ( i = 0; i < 8; i++ ) {
2629 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2630 if ( !n ) return false;
2631 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2632 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2634 DUMPSO( "========================================");
2637 set<int> faceNodes; // ids of bottom face nodes, to be found
2638 set<int> checkedId1; // ids of tried 2-nd nodes
2639 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2640 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2641 int iMin, iLoop1 = 0;
2643 // Loop to try the 2-nd nodes
2645 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2647 // Find not checked 2-nd node
2648 for ( i = 1; i < 8; i++ )
2649 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2650 int id1 = idNodes[i];
2651 swap ( 1, i, idNodes, P );
2652 checkedId1.insert ( id1 );
2656 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2657 // ie that all but meybe one (id3 which is on the same face) nodes
2658 // lay on the same side from the triangle plane.
2660 bool manyInPlane = false; // more than 4 nodes lay in plane
2662 while ( ++iLoop2 < 6 ) {
2664 // get 1-2-3 plane coeffs
2665 Standard_Real A, B, C, D;
2666 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2667 if ( N.SquareMagnitude() > gp::Resolution() )
2669 gp_Pln pln ( P[0], N );
2670 pln.Coefficients( A, B, C, D );
2672 // find the node (iMin) closest to pln
2673 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2675 for ( i = 3; i < 8; i++ ) {
2676 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2677 if ( fabs( dist[i] ) < minDist ) {
2678 minDist = fabs( dist[i] );
2681 if ( fabs( dist[i] ) <= tol )
2682 idInPln.insert( idNodes[i] );
2685 // there should not be more than 4 nodes in bottom plane
2686 if ( idInPln.size() > 1 )
2688 DUMPSO( "### idInPln.size() = " << idInPln.size());
2689 // idInPlane does not contain the first 3 nodes
2690 if ( manyInPlane || idInPln.size() == 5)
2691 return false; // all nodes in one plane
2694 // set the 1-st node to be not in plane
2695 for ( i = 3; i < 8; i++ ) {
2696 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2697 DUMPSO( "### Reset 0-th node");
2698 swap( 0, i, idNodes, P );
2703 // reset to re-check second nodes
2704 leastDist = DBL_MAX;
2708 break; // from iLoop2;
2711 // check that the other 4 nodes are on the same side
2712 bool sameSide = true;
2713 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2714 for ( i = 3; sameSide && i < 8; i++ ) {
2716 sameSide = ( isNeg == dist[i] <= 0.);
2719 // keep best solution
2720 if ( sameSide && minDist < leastDist ) {
2721 leastDist = minDist;
2723 faceNodes.insert( idNodes[ 1 ] );
2724 faceNodes.insert( idNodes[ 2 ] );
2725 faceNodes.insert( idNodes[ iMin ] );
2726 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2727 << " leastDist = " << leastDist);
2728 if ( leastDist <= DBL_MIN )
2733 // set next 3-d node to check
2734 int iNext = 2 + iLoop2;
2736 DUMPSO( "Try 2-nd");
2737 swap ( 2, iNext, idNodes, P );
2739 } // while ( iLoop2 < 6 )
2742 if ( faceNodes.empty() ) return false;
2744 // Put the faceNodes in proper places
2745 for ( i = 4; i < 8; i++ ) {
2746 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2747 // find a place to put
2749 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2751 DUMPSO( "Set faceNodes");
2752 swap ( iTo, i, idNodes, P );
2757 // Set nodes of the found bottom face in good order
2758 DUMPSO( " Found bottom face: ");
2759 i = SortQuadNodes( theMesh, idNodes );
2761 gp_Pnt Ptmp = P[ i ];
2766 // for ( int ii = 0; ii < 4; ii++ ) {
2767 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2768 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2771 // Gravity center of the top and bottom faces
2772 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2773 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2775 // Get direction from the bottom to the top face
2776 gp_Vec upDir ( aGCb, aGCt );
2777 Standard_Real upDirSize = upDir.Magnitude();
2778 if ( upDirSize <= gp::Resolution() ) return false;
2781 // Assure that the bottom face normal points up
2782 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2783 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2784 if ( Nb.Dot( upDir ) < 0 ) {
2785 DUMPSO( "Reverse bottom face");
2786 swap( 1, 3, idNodes, P );
2789 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2790 Standard_Real minDist = DBL_MAX;
2791 for ( i = 4; i < 8; i++ ) {
2792 // projection of P[i] to the plane defined by P[0] and upDir
2793 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2794 Standard_Real sqDist = P[0].SquareDistance( Pp );
2795 if ( sqDist < minDist ) {
2800 DUMPSO( "Set 4-th");
2801 swap ( 4, iMin, idNodes, P );
2803 // Set nodes of the top face in good order
2804 DUMPSO( "Sort top face");
2805 i = SortQuadNodes( theMesh, &idNodes[4] );
2808 gp_Pnt Ptmp = P[ i ];
2813 // Assure that direction of the top face normal is from the bottom face
2814 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2815 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2816 if ( Nt.Dot( upDir ) < 0 ) {
2817 DUMPSO( "Reverse top face");
2818 swap( 5, 7, idNodes, P );
2821 // DUMPSO( "OUTPUT: ========================================");
2822 // for ( i = 0; i < 8; i++ ) {
2823 // float *p = ugrid->GetPoint(idNodes[i]);
2824 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2830 //================================================================================
2832 * \brief Return nodes linked to the given one
2833 * \param theNode - the node
2834 * \param linkedNodes - the found nodes
2835 * \param type - the type of elements to check
2837 * Medium nodes are ignored
2839 //================================================================================
2841 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2842 TIDSortedElemSet & linkedNodes,
2843 SMDSAbs_ElementType type )
2845 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2846 while ( elemIt->more() )
2848 const SMDS_MeshElement* elem = elemIt->next();
2849 if(elem->GetType() == SMDSAbs_0DElement)
2852 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2853 if ( elem->GetType() == SMDSAbs_Volume )
2855 SMDS_VolumeTool vol( elem );
2856 while ( nodeIt->more() ) {
2857 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2858 if ( theNode != n && vol.IsLinked( theNode, n ))
2859 linkedNodes.insert( n );
2864 for ( int i = 0; nodeIt->more(); ++i ) {
2865 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2866 if ( n == theNode ) {
2867 int iBefore = i - 1;
2869 if ( elem->IsQuadratic() ) {
2870 int nb = elem->NbNodes() / 2;
2871 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2872 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2874 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2875 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2882 //=======================================================================
2883 //function : laplacianSmooth
2884 //purpose : pulls theNode toward the center of surrounding nodes directly
2885 // connected to that node along an element edge
2886 //=======================================================================
2888 void laplacianSmooth(const SMDS_MeshNode* theNode,
2889 const Handle(Geom_Surface)& theSurface,
2890 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2892 // find surrounding nodes
2894 TIDSortedElemSet nodeSet;
2895 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2897 // compute new coodrs
2899 double coord[] = { 0., 0., 0. };
2900 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2901 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2902 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2903 if ( theSurface.IsNull() ) { // smooth in 3D
2904 coord[0] += node->X();
2905 coord[1] += node->Y();
2906 coord[2] += node->Z();
2908 else { // smooth in 2D
2909 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2910 gp_XY* uv = theUVMap[ node ];
2911 coord[0] += uv->X();
2912 coord[1] += uv->Y();
2915 int nbNodes = nodeSet.size();
2918 coord[0] /= nbNodes;
2919 coord[1] /= nbNodes;
2921 if ( !theSurface.IsNull() ) {
2922 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2923 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2924 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2930 coord[2] /= nbNodes;
2934 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2937 //=======================================================================
2938 //function : centroidalSmooth
2939 //purpose : pulls theNode toward the element-area-weighted centroid of the
2940 // surrounding elements
2941 //=======================================================================
2943 void centroidalSmooth(const SMDS_MeshNode* theNode,
2944 const Handle(Geom_Surface)& theSurface,
2945 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2947 gp_XYZ aNewXYZ(0.,0.,0.);
2948 SMESH::Controls::Area anAreaFunc;
2949 double totalArea = 0.;
2954 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2955 while ( elemIt->more() )
2957 const SMDS_MeshElement* elem = elemIt->next();
2960 gp_XYZ elemCenter(0.,0.,0.);
2961 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2962 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2963 int nn = elem->NbNodes();
2964 if(elem->IsQuadratic()) nn = nn/2;
2966 //while ( itN->more() ) {
2968 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2970 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2971 aNodePoints.push_back( aP );
2972 if ( !theSurface.IsNull() ) { // smooth in 2D
2973 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2974 gp_XY* uv = theUVMap[ aNode ];
2975 aP.SetCoord( uv->X(), uv->Y(), 0. );
2979 double elemArea = anAreaFunc.GetValue( aNodePoints );
2980 totalArea += elemArea;
2982 aNewXYZ += elemCenter * elemArea;
2984 aNewXYZ /= totalArea;
2985 if ( !theSurface.IsNull() ) {
2986 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2987 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2992 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2995 //=======================================================================
2996 //function : getClosestUV
2997 //purpose : return UV of closest projection
2998 //=======================================================================
3000 static bool getClosestUV (Extrema_GenExtPS& projector,
3001 const gp_Pnt& point,
3004 projector.Perform( point );
3005 if ( projector.IsDone() ) {
3006 double u, v, minVal = DBL_MAX;
3007 for ( int i = projector.NbExt(); i > 0; i-- )
3008 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3009 if ( projector.SquareDistance( i ) < minVal ) {
3010 minVal = projector.SquareDistance( i );
3012 if ( projector.Value( i ) < minVal ) {
3013 minVal = projector.Value( i );
3015 projector.Point( i ).Parameter( u, v );
3017 result.SetCoord( u, v );
3023 //=======================================================================
3025 //purpose : Smooth theElements during theNbIterations or until a worst
3026 // element has aspect ratio <= theTgtAspectRatio.
3027 // Aspect Ratio varies in range [1.0, inf].
3028 // If theElements is empty, the whole mesh is smoothed.
3029 // theFixedNodes contains additionally fixed nodes. Nodes built
3030 // on edges and boundary nodes are always fixed.
3031 //=======================================================================
3033 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
3034 set<const SMDS_MeshNode*> & theFixedNodes,
3035 const SmoothMethod theSmoothMethod,
3036 const int theNbIterations,
3037 double theTgtAspectRatio,
3040 myLastCreatedElems.Clear();
3041 myLastCreatedNodes.Clear();
3043 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3045 if ( theTgtAspectRatio < 1.0 )
3046 theTgtAspectRatio = 1.0;
3048 const double disttol = 1.e-16;
3050 SMESH::Controls::AspectRatio aQualityFunc;
3052 SMESHDS_Mesh* aMesh = GetMeshDS();
3054 if ( theElems.empty() ) {
3055 // add all faces to theElems
3056 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3057 while ( fIt->more() ) {
3058 const SMDS_MeshElement* face = fIt->next();
3059 theElems.insert( face );
3062 // get all face ids theElems are on
3063 set< int > faceIdSet;
3064 TIDSortedElemSet::iterator itElem;
3066 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3067 int fId = FindShape( *itElem );
3068 // check that corresponding submesh exists and a shape is face
3070 faceIdSet.find( fId ) == faceIdSet.end() &&
3071 aMesh->MeshElements( fId )) {
3072 TopoDS_Shape F = aMesh->IndexToShape( fId );
3073 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3074 faceIdSet.insert( fId );
3077 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3079 // ===============================================
3080 // smooth elements on each TopoDS_Face separately
3081 // ===============================================
3083 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3084 for ( ; fId != faceIdSet.rend(); ++fId ) {
3085 // get face surface and submesh
3086 Handle(Geom_Surface) surface;
3087 SMESHDS_SubMesh* faceSubMesh = 0;
3089 double fToler2 = 0, f,l;
3090 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3091 bool isUPeriodic = false, isVPeriodic = false;
3093 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3094 surface = BRep_Tool::Surface( face );
3095 faceSubMesh = aMesh->MeshElements( *fId );
3096 fToler2 = BRep_Tool::Tolerance( face );
3097 fToler2 *= fToler2 * 10.;
3098 isUPeriodic = surface->IsUPeriodic();
3101 isVPeriodic = surface->IsVPeriodic();
3104 surface->Bounds( u1, u2, v1, v2 );
3106 // ---------------------------------------------------------
3107 // for elements on a face, find movable and fixed nodes and
3108 // compute UV for them
3109 // ---------------------------------------------------------
3110 bool checkBoundaryNodes = false;
3111 bool isQuadratic = false;
3112 set<const SMDS_MeshNode*> setMovableNodes;
3113 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3114 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3115 list< const SMDS_MeshElement* > elemsOnFace;
3117 Extrema_GenExtPS projector;
3118 GeomAdaptor_Surface surfAdaptor;
3119 if ( !surface.IsNull() ) {
3120 surfAdaptor.Load( surface );
3121 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3123 int nbElemOnFace = 0;
3124 itElem = theElems.begin();
3125 // loop on not yet smoothed elements: look for elems on a face
3126 while ( itElem != theElems.end() ) {
3127 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3128 break; // all elements found
3130 const SMDS_MeshElement* elem = *itElem;
3131 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3132 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3136 elemsOnFace.push_back( elem );
3137 theElems.erase( itElem++ );
3141 isQuadratic = elem->IsQuadratic();
3143 // get movable nodes of elem
3144 const SMDS_MeshNode* node;
3145 SMDS_TypeOfPosition posType;
3146 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3147 int nn = 0, nbn = elem->NbNodes();
3148 if(elem->IsQuadratic())
3150 while ( nn++ < nbn ) {
3151 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3152 const SMDS_PositionPtr& pos = node->GetPosition();
3153 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3154 if (posType != SMDS_TOP_EDGE &&
3155 posType != SMDS_TOP_VERTEX &&
3156 theFixedNodes.find( node ) == theFixedNodes.end())
3158 // check if all faces around the node are on faceSubMesh
3159 // because a node on edge may be bound to face
3160 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3162 if ( faceSubMesh ) {
3163 while ( eIt->more() && all ) {
3164 const SMDS_MeshElement* e = eIt->next();
3165 all = faceSubMesh->Contains( e );
3169 setMovableNodes.insert( node );
3171 checkBoundaryNodes = true;
3173 if ( posType == SMDS_TOP_3DSPACE )
3174 checkBoundaryNodes = true;
3177 if ( surface.IsNull() )
3180 // get nodes to check UV
3181 list< const SMDS_MeshNode* > uvCheckNodes;
3182 itN = elem->nodesIterator();
3183 nn = 0; nbn = elem->NbNodes();
3184 if(elem->IsQuadratic())
3186 while ( nn++ < nbn ) {
3187 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3188 if ( uvMap.find( node ) == uvMap.end() )
3189 uvCheckNodes.push_back( node );
3190 // add nodes of elems sharing node
3191 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3192 // while ( eIt->more() ) {
3193 // const SMDS_MeshElement* e = eIt->next();
3194 // if ( e != elem ) {
3195 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3196 // while ( nIt->more() ) {
3197 // const SMDS_MeshNode* n =
3198 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3199 // if ( uvMap.find( n ) == uvMap.end() )
3200 // uvCheckNodes.push_back( n );
3206 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3207 for ( ; n != uvCheckNodes.end(); ++n ) {
3210 const SMDS_PositionPtr& pos = node->GetPosition();
3211 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3213 switch ( posType ) {
3214 case SMDS_TOP_FACE: {
3215 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3216 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3219 case SMDS_TOP_EDGE: {
3220 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3221 Handle(Geom2d_Curve) pcurve;
3222 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3223 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3224 if ( !pcurve.IsNull() ) {
3225 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3226 uv = pcurve->Value( u ).XY();
3230 case SMDS_TOP_VERTEX: {
3231 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3232 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3233 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3238 // check existing UV
3239 bool project = true;
3240 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3241 double dist1 = DBL_MAX, dist2 = 0;
3242 if ( posType != SMDS_TOP_3DSPACE ) {
3243 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3244 project = dist1 > fToler2;
3246 if ( project ) { // compute new UV
3248 if ( !getClosestUV( projector, pNode, newUV )) {
3249 MESSAGE("Node Projection Failed " << node);
3253 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3255 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3257 if ( posType != SMDS_TOP_3DSPACE )
3258 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3259 if ( dist2 < dist1 )
3263 // store UV in the map
3264 listUV.push_back( uv );
3265 uvMap.insert( make_pair( node, &listUV.back() ));
3267 } // loop on not yet smoothed elements
3269 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3270 checkBoundaryNodes = true;
3272 // fix nodes on mesh boundary
3274 if ( checkBoundaryNodes ) {
3275 map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3276 map< SMESH_TLink, int >::iterator link_nb;
3277 // put all elements links to linkNbMap
3278 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3279 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3280 const SMDS_MeshElement* elem = (*elemIt);
3281 int nbn = elem->NbCornerNodes();
3282 // loop on elem links: insert them in linkNbMap
3283 for ( int iN = 0; iN < nbn; ++iN ) {
3284 const SMDS_MeshNode* n1 = elem->GetNode( iN );
3285 const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3286 SMESH_TLink link( n1, n2 );
3287 link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3291 // remove nodes that are in links encountered only once from setMovableNodes
3292 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3293 if ( link_nb->second == 1 ) {
3294 setMovableNodes.erase( link_nb->first.node1() );
3295 setMovableNodes.erase( link_nb->first.node2() );
3300 // -----------------------------------------------------
3301 // for nodes on seam edge, compute one more UV ( uvMap2 );
3302 // find movable nodes linked to nodes on seam and which
3303 // are to be smoothed using the second UV ( uvMap2 )
3304 // -----------------------------------------------------
3306 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3307 if ( !surface.IsNull() ) {
3308 TopExp_Explorer eExp( face, TopAbs_EDGE );
3309 for ( ; eExp.More(); eExp.Next() ) {
3310 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3311 if ( !BRep_Tool::IsClosed( edge, face ))
3313 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3314 if ( !sm ) continue;
3315 // find out which parameter varies for a node on seam
3318 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3319 if ( pcurve.IsNull() ) continue;
3320 uv1 = pcurve->Value( f );
3322 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3323 if ( pcurve.IsNull() ) continue;
3324 uv2 = pcurve->Value( f );
3325 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3327 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3328 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3330 // get nodes on seam and its vertices
3331 list< const SMDS_MeshNode* > seamNodes;
3332 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3333 while ( nSeamIt->more() ) {
3334 const SMDS_MeshNode* node = nSeamIt->next();
3335 if ( !isQuadratic || !IsMedium( node ))
3336 seamNodes.push_back( node );
3338 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3339 for ( ; vExp.More(); vExp.Next() ) {
3340 sm = aMesh->MeshElements( vExp.Current() );
3342 nSeamIt = sm->GetNodes();
3343 while ( nSeamIt->more() )
3344 seamNodes.push_back( nSeamIt->next() );
3347 // loop on nodes on seam
3348 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3349 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3350 const SMDS_MeshNode* nSeam = *noSeIt;
3351 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3352 if ( n_uv == uvMap.end() )
3355 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3356 // set the second UV
3357 listUV.push_back( *n_uv->second );
3358 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3359 if ( uvMap2.empty() )
3360 uvMap2 = uvMap; // copy the uvMap contents
3361 uvMap2[ nSeam ] = &listUV.back();
3363 // collect movable nodes linked to ones on seam in nodesNearSeam
3364 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3365 while ( eIt->more() ) {
3366 const SMDS_MeshElement* e = eIt->next();
3367 int nbUseMap1 = 0, nbUseMap2 = 0;
3368 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3369 int nn = 0, nbn = e->NbNodes();
3370 if(e->IsQuadratic()) nbn = nbn/2;
3371 while ( nn++ < nbn )
3373 const SMDS_MeshNode* n =
3374 static_cast<const SMDS_MeshNode*>( nIt->next() );
3376 setMovableNodes.find( n ) == setMovableNodes.end() )
3378 // add only nodes being closer to uv2 than to uv1
3379 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3380 0.5 * ( n->Y() + nSeam->Y() ),
3381 0.5 * ( n->Z() + nSeam->Z() ));
3383 getClosestUV( projector, pMid, uv );
3384 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3385 nodesNearSeam.insert( n );
3391 // for centroidalSmooth all element nodes must
3392 // be on one side of a seam
3393 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3394 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3396 while ( nn++ < nbn ) {
3397 const SMDS_MeshNode* n =
3398 static_cast<const SMDS_MeshNode*>( nIt->next() );
3399 setMovableNodes.erase( n );
3403 } // loop on nodes on seam
3404 } // loop on edge of a face
3405 } // if ( !face.IsNull() )
3407 if ( setMovableNodes.empty() ) {
3408 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3409 continue; // goto next face
3417 double maxRatio = -1., maxDisplacement = -1.;
3418 set<const SMDS_MeshNode*>::iterator nodeToMove;
3419 for ( it = 0; it < theNbIterations; it++ ) {
3420 maxDisplacement = 0.;
3421 nodeToMove = setMovableNodes.begin();
3422 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3423 const SMDS_MeshNode* node = (*nodeToMove);
3424 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3427 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3428 if ( theSmoothMethod == LAPLACIAN )
3429 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3431 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3433 // node displacement
3434 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3435 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3436 if ( aDispl > maxDisplacement )
3437 maxDisplacement = aDispl;
3439 // no node movement => exit
3440 //if ( maxDisplacement < 1.e-16 ) {
3441 if ( maxDisplacement < disttol ) {
3442 MESSAGE("-- no node movement --");
3446 // check elements quality
3448 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3449 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3450 const SMDS_MeshElement* elem = (*elemIt);
3451 if ( !elem || elem->GetType() != SMDSAbs_Face )
3453 SMESH::Controls::TSequenceOfXYZ aPoints;
3454 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3455 double aValue = aQualityFunc.GetValue( aPoints );
3456 if ( aValue > maxRatio )
3460 if ( maxRatio <= theTgtAspectRatio ) {
3461 MESSAGE("-- quality achived --");
3464 if (it+1 == theNbIterations) {
3465 MESSAGE("-- Iteration limit exceeded --");
3467 } // smoothing iterations
3469 MESSAGE(" Face id: " << *fId <<
3470 " Nb iterstions: " << it <<
3471 " Displacement: " << maxDisplacement <<
3472 " Aspect Ratio " << maxRatio);
3474 // ---------------------------------------
3475 // new nodes positions are computed,
3476 // record movement in DS and set new UV
3477 // ---------------------------------------
3478 nodeToMove = setMovableNodes.begin();
3479 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3480 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3481 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3482 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3483 if ( node_uv != uvMap.end() ) {
3484 gp_XY* uv = node_uv->second;
3486 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3490 // move medium nodes of quadratic elements
3493 SMESH_MesherHelper helper( *GetMesh() );
3494 if ( !face.IsNull() )
3495 helper.SetSubShape( face );
3496 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3497 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3498 const SMDS_VtkFace* QF =
3499 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3500 if(QF && QF->IsQuadratic()) {
3501 vector<const SMDS_MeshNode*> Ns;
3502 Ns.reserve(QF->NbNodes()+1);
3503 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3504 while ( anIter->more() )
3505 Ns.push_back( cast2Node(anIter->next()) );
3506 Ns.push_back( Ns[0] );
3508 for(int i=0; i<QF->NbNodes(); i=i+2) {
3509 if ( !surface.IsNull() ) {
3510 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3511 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3512 gp_XY uv = ( uv1 + uv2 ) / 2.;
3513 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3514 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3517 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3518 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3519 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3521 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3522 fabs( Ns[i+1]->Y() - y ) > disttol ||
3523 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3524 // we have to move i+1 node
3525 aMesh->MoveNode( Ns[i+1], x, y, z );
3532 } // loop on face ids
3536 //=======================================================================
3537 //function : isReverse
3538 //purpose : Return true if normal of prevNodes is not co-directied with
3539 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3540 // iNotSame is where prevNodes and nextNodes are different.
3541 // If result is true then future volume orientation is OK
3542 //=======================================================================
3544 static bool isReverse(const SMDS_MeshElement* face,
3545 const vector<const SMDS_MeshNode*>& prevNodes,
3546 const vector<const SMDS_MeshNode*>& nextNodes,
3550 SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3551 SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3552 gp_XYZ extrDir( pN - pP ), faceNorm;
3553 SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3555 return faceNorm * extrDir < 0.0;
3558 //=======================================================================
3560 * \brief Create elements by sweeping an element
3561 * \param elem - element to sweep
3562 * \param newNodesItVec - nodes generated from each node of the element
3563 * \param newElems - generated elements
3564 * \param nbSteps - number of sweeping steps
3565 * \param srcElements - to append elem for each generated element
3567 //=======================================================================
3569 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3570 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3571 list<const SMDS_MeshElement*>& newElems,
3573 SMESH_SequenceOfElemPtr& srcElements)
3575 //MESSAGE("sweepElement " << nbSteps);
3576 SMESHDS_Mesh* aMesh = GetMeshDS();
3578 const int nbNodes = elem->NbNodes();
3579 const int nbCorners = elem->NbCornerNodes();
3580 SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3581 polyhedron creation !!! */
3582 // Loop on elem nodes:
3583 // find new nodes and detect same nodes indices
3584 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3585 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3586 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3587 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3589 int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3590 vector<int> sames(nbNodes);
3591 vector<bool> isSingleNode(nbNodes);
3593 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3594 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3595 const SMDS_MeshNode* node = nnIt->first;
3596 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3597 if ( listNewNodes.empty() )
3600 itNN [ iNode ] = listNewNodes.begin();
3601 prevNod[ iNode ] = node;
3602 nextNod[ iNode ] = listNewNodes.front();
3604 isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3605 corner node of linear */
3606 if ( prevNod[ iNode ] != nextNod [ iNode ])
3607 nbDouble += !isSingleNode[iNode];
3609 if( iNode < nbCorners ) { // check corners only
3610 if ( prevNod[ iNode ] == nextNod [ iNode ])
3611 sames[nbSame++] = iNode;
3613 iNotSameNode = iNode;
3617 if ( nbSame == nbNodes || nbSame > 2) {
3618 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3622 if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3624 // fix nodes order to have bottom normal external
3625 if ( baseType == SMDSEntity_Polygon )
3627 std::reverse( itNN.begin(), itNN.end() );
3628 std::reverse( prevNod.begin(), prevNod.end() );
3629 std::reverse( midlNod.begin(), midlNod.end() );
3630 std::reverse( nextNod.begin(), nextNod.end() );
3631 std::reverse( isSingleNode.begin(), isSingleNode.end() );
3635 const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3636 SMDS_MeshCell::applyInterlace( ind, itNN );
3637 SMDS_MeshCell::applyInterlace( ind, prevNod );
3638 SMDS_MeshCell::applyInterlace( ind, nextNod );
3639 SMDS_MeshCell::applyInterlace( ind, midlNod );
3640 SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3643 sames[nbSame] = iNotSameNode;
3644 for ( int j = 0; j <= nbSame; ++j )
3645 for ( size_t i = 0; i < ind.size(); ++i )
3646 if ( ind[i] == sames[j] )
3651 iNotSameNode = sames[nbSame];
3656 int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3658 iSameNode = sames[ nbSame-1 ];
3659 iBeforeSame = ( iSameNode + nbCorners - 1 ) % nbCorners;
3660 iAfterSame = ( iSameNode + 1 ) % nbCorners;
3661 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3664 // make new elements
3665 for (int iStep = 0; iStep < nbSteps; iStep++ )
3668 for ( iNode = 0; iNode < nbNodes; iNode++ )
3670 midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3671 nextNod[ iNode ] = *itNN[ iNode ]++;
3674 SMDS_MeshElement* aNewElem = 0;
3675 /*if(!elem->IsPoly())*/ {
3676 switch ( baseType ) {
3678 case SMDSEntity_Node: { // sweep NODE
3679 if ( nbSame == 0 ) {
3680 if ( isSingleNode[0] )
3681 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3683 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3689 case SMDSEntity_Edge: { // sweep EDGE
3690 if ( nbDouble == 0 )
3692 if ( nbSame == 0 ) // ---> quadrangle
3693 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3694 nextNod[ 1 ], nextNod[ 0 ] );
3695 else // ---> triangle
3696 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3697 nextNod[ iNotSameNode ] );
3699 else // ---> polygon
3701 vector<const SMDS_MeshNode*> poly_nodes;
3702 poly_nodes.push_back( prevNod[0] );
3703 poly_nodes.push_back( prevNod[1] );
3704 if ( prevNod[1] != nextNod[1] )
3706 if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3707 poly_nodes.push_back( nextNod[1] );
3709 if ( prevNod[0] != nextNod[0] )
3711 poly_nodes.push_back( nextNod[0] );
3712 if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3714 switch ( poly_nodes.size() ) {
3716 aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3719 aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3720 poly_nodes[ 2 ], poly_nodes[ 3 ]);
3723 aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3728 case SMDSEntity_Triangle: // TRIANGLE --->
3730 if ( nbDouble > 0 ) break;
3731 if ( nbSame == 0 ) // ---> pentahedron
3732 aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3733 nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3735 else if ( nbSame == 1 ) // ---> pyramid
3736 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3737 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3738 nextNod[ iSameNode ]);
3740 else // 2 same nodes: ---> tetrahedron
3741 aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3742 nextNod[ iNotSameNode ]);
3745 case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3749 if ( nbDouble+nbSame == 2 )
3751 if(nbSame==0) { // ---> quadratic quadrangle
3752 aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3753 prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3755 else { //(nbSame==1) // ---> quadratic triangle
3757 return; // medium node on axis
3759 else if(sames[0]==0)
3760 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3761 nextNod[2], midlNod[1], prevNod[2]);
3763 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3764 midlNod[0], nextNod[2], prevNod[2]);
3767 else if ( nbDouble == 3 )
3769 if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle
3770 aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3771 prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3778 case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3779 if ( nbDouble > 0 ) break;
3781 if ( nbSame == 0 ) // ---> hexahedron
3782 aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3783 nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3785 else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3786 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3787 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3788 nextNod[ iSameNode ]);
3789 newElems.push_back( aNewElem );
3790 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3791 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3792 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3794 else if ( nbSame == 2 ) { // ---> pentahedron
3795 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3796 // iBeforeSame is same too
3797 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3798 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3799 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3801 // iAfterSame is same too
3802 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3803 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3804 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3808 case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3809 if ( nbDouble+nbSame != 3 ) break;
3811 // ---> pentahedron with 15 nodes
3812 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3813 nextNod[0], nextNod[1], nextNod[2],
3814 prevNod[3], prevNod[4], prevNod[5],
3815 nextNod[3], nextNod[4], nextNod[5],
3816 midlNod[0], midlNod[1], midlNod[2]);
3818 else if(nbSame==1) {
3819 // ---> 2d order pyramid of 13 nodes
3820 int apex = iSameNode;
3821 int i0 = ( apex + 1 ) % nbCorners;
3822 int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3826 aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3827 nextNod[i0], nextNod[i1], prevNod[apex],
3828 prevNod[i01], midlNod[i0],
3829 nextNod[i01], midlNod[i1],
3830 prevNod[i1a], prevNod[i0a],
3831 nextNod[i0a], nextNod[i1a]);
3833 else if(nbSame==2) {
3834 // ---> 2d order tetrahedron of 10 nodes
3835 int n1 = iNotSameNode;
3836 int n2 = ( n1 + 1 ) % nbCorners;
3837 int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3841 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3842 prevNod[n12], prevNod[n23], prevNod[n31],
3843 midlNod[n1], nextNod[n12], nextNod[n31]);
3847 case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3849 if ( nbDouble != 4 ) break;
3850 // ---> hexahedron with 20 nodes
3851 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3852 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3853 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3854 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3855 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3857 else if(nbSame==1) {
3858 // ---> pyramid + pentahedron - can not be created since it is needed
3859 // additional middle node at the center of face
3860 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3863 else if( nbSame == 2 ) {
3864 if ( nbDouble != 2 ) break;
3865 // ---> 2d order Pentahedron with 15 nodes
3867 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3868 // iBeforeSame is same too
3875 // iAfterSame is same too
3885 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3886 prevNod[n4], prevNod[n5], nextNod[n5],
3887 prevNod[n12], midlNod[n2], nextNod[n12],
3888 prevNod[n45], midlNod[n5], nextNod[n45],
3889 prevNod[n14], prevNod[n25], nextNod[n25]);
3893 case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3895 if( nbSame == 0 && nbDouble == 9 ) {
3896 // ---> tri-quadratic hexahedron with 27 nodes
3897 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3898 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3899 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3900 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3901 midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3902 prevNod[8], // bottom center
3903 midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3904 nextNod[8], // top center
3905 midlNod[8]);// elem center
3913 case SMDSEntity_Polygon: { // sweep POLYGON
3915 if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3916 // ---> hexagonal prism
3917 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3918 prevNod[3], prevNod[4], prevNod[5],
3919 nextNod[0], nextNod[1], nextNod[2],
3920 nextNod[3], nextNod[4], nextNod[5]);
3929 if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3931 if ( baseType != SMDSEntity_Polygon )
3933 const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3934 SMDS_MeshCell::applyInterlace( ind, prevNod );
3935 SMDS_MeshCell::applyInterlace( ind, nextNod );
3936 SMDS_MeshCell::applyInterlace( ind, midlNod );
3937 SMDS_MeshCell::applyInterlace( ind, itNN );
3938 SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3939 baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3941 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3942 vector<int> quantities (nbNodes + 2);
3943 polyedre_nodes.clear();
3947 for (int inode = 0; inode < nbNodes; inode++)
3948 polyedre_nodes.push_back( prevNod[inode] );
3949 quantities.push_back( nbNodes );
3952 polyedre_nodes.push_back( nextNod[0] );
3953 for (int inode = nbNodes; inode-1; --inode )
3954 polyedre_nodes.push_back( nextNod[inode-1] );
3955 quantities.push_back( nbNodes );
3958 for (int iface = 0; iface < nbNodes; iface++)
3960 const int prevNbNodes = polyedre_nodes.size();
3961 int inextface = (iface+1) % nbNodes;
3962 polyedre_nodes.push_back( prevNod[inextface] );
3963 polyedre_nodes.push_back( prevNod[iface] );
3964 if ( prevNod[iface] != nextNod[iface] )
3966 if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
3967 polyedre_nodes.push_back( nextNod[iface] );
3969 if ( prevNod[inextface] != nextNod[inextface] )
3971 polyedre_nodes.push_back( nextNod[inextface] );
3972 if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
3974 const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
3975 if ( nbFaceNodes > 2 )
3976 quantities.push_back( nbFaceNodes );
3977 else // degenerated face
3978 polyedre_nodes.resize( prevNbNodes );
3980 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3984 newElems.push_back( aNewElem );
3985 myLastCreatedElems.Append(aNewElem);
3986 srcElements.Append( elem );
3989 // set new prev nodes
3990 for ( iNode = 0; iNode < nbNodes; iNode++ )
3991 prevNod[ iNode ] = nextNod[ iNode ];
3996 //=======================================================================
3998 * \brief Create 1D and 2D elements around swept elements
3999 * \param mapNewNodes - source nodes and ones generated from them
4000 * \param newElemsMap - source elements and ones generated from them
4001 * \param elemNewNodesMap - nodes generated from each node of each element
4002 * \param elemSet - all swept elements
4003 * \param nbSteps - number of sweeping steps
4004 * \param srcElements - to append elem for each generated element
4006 //=======================================================================
4008 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
4009 TElemOfElemListMap & newElemsMap,
4010 TElemOfVecOfNnlmiMap & elemNewNodesMap,
4011 TIDSortedElemSet& elemSet,
4013 SMESH_SequenceOfElemPtr& srcElements)
4015 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4016 SMESHDS_Mesh* aMesh = GetMeshDS();
4018 // Find nodes belonging to only one initial element - sweep them to get edges.
4020 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4021 for ( ; nList != mapNewNodes.end(); nList++ )
4023 const SMDS_MeshNode* node =
4024 static_cast<const SMDS_MeshNode*>( nList->first );
4025 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4026 int nbInitElems = 0;
4027 const SMDS_MeshElement* el = 0;
4028 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4029 while ( eIt->more() && nbInitElems < 2 ) {
4031 SMDSAbs_ElementType type = el->GetType();
4032 if ( type == SMDSAbs_Volume || type < highType ) continue;
4033 if ( type > highType ) {
4037 nbInitElems += elemSet.count(el);
4039 if ( nbInitElems < 2 ) {
4040 bool NotCreateEdge = el && el->IsMediumNode(node);
4041 if(!NotCreateEdge) {
4042 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4043 list<const SMDS_MeshElement*> newEdges;
4044 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4049 // Make a ceiling for each element ie an equal element of last new nodes.
4050 // Find free links of faces - make edges and sweep them into faces.
4052 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
4053 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4054 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4056 const SMDS_MeshElement* elem = itElem->first;
4057 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4059 if(itElem->second.size()==0) continue;
4061 const bool isQuadratic = elem->IsQuadratic();
4063 if ( elem->GetType() == SMDSAbs_Edge ) {
4064 // create a ceiling edge
4065 if ( !isQuadratic ) {
4066 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4067 vecNewNodes[ 1 ]->second.back())) {
4068 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4069 vecNewNodes[ 1 ]->second.back()));
4070 srcElements.Append( myLastCreatedElems.Last() );
4074 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4075 vecNewNodes[ 1 ]->second.back(),
4076 vecNewNodes[ 2 ]->second.back())) {
4077 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4078 vecNewNodes[ 1 ]->second.back(),
4079 vecNewNodes[ 2 ]->second.back()));
4080 srcElements.Append( myLastCreatedElems.Last() );
4084 if ( elem->GetType() != SMDSAbs_Face )
4087 bool hasFreeLinks = false;
4089 TIDSortedElemSet avoidSet;
4090 avoidSet.insert( elem );
4092 set<const SMDS_MeshNode*> aFaceLastNodes;
4093 int iNode, nbNodes = vecNewNodes.size();
4094 if ( !isQuadratic ) {
4095 // loop on the face nodes
4096 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4097 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4098 // look for free links of the face
4099 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4100 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4101 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4102 // check if a link is free
4103 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4104 hasFreeLinks = true;
4105 // make an edge and a ceiling for a new edge
4106 if ( !aMesh->FindEdge( n1, n2 )) {
4107 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4108 srcElements.Append( myLastCreatedElems.Last() );
4110 n1 = vecNewNodes[ iNode ]->second.back();
4111 n2 = vecNewNodes[ iNext ]->second.back();
4112 if ( !aMesh->FindEdge( n1, n2 )) {
4113 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4114 srcElements.Append( myLastCreatedElems.Last() );
4119 else { // elem is quadratic face
4120 int nbn = nbNodes/2;
4121 for ( iNode = 0; iNode < nbn; iNode++ ) {
4122 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4123 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4124 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4125 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4126 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4127 // check if a link is free
4128 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4129 ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4130 ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4131 hasFreeLinks = true;
4132 // make an edge and a ceiling for a new edge
4134 if ( !aMesh->FindEdge( n1, n2, n3 )) {
4135 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4136 srcElements.Append( myLastCreatedElems.Last() );
4138 n1 = vecNewNodes[ iNode ]->second.back();
4139 n2 = vecNewNodes[ iNext ]->second.back();
4140 n3 = vecNewNodes[ iNode+nbn ]->second.back();
4141 if ( !aMesh->FindEdge( n1, n2, n3 )) {
4142 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4143 srcElements.Append( myLastCreatedElems.Last() );
4147 for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4148 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4152 // sweep free links into faces
4154 if ( hasFreeLinks ) {
4155 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4156 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4158 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4159 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4160 initNodeSet.insert( vecNewNodes[ iNode ]->first );
4161 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4163 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4164 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4165 std::advance( v, volNb );
4166 // find indices of free faces of a volume and their source edges
4167 list< int > freeInd;
4168 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4169 SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4170 int iF, nbF = vTool.NbFaces();
4171 for ( iF = 0; iF < nbF; iF ++ ) {
4172 if (vTool.IsFreeFace( iF ) &&
4173 vTool.GetFaceNodes( iF, faceNodeSet ) &&
4174 initNodeSet != faceNodeSet) // except an initial face
4176 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4178 freeInd.push_back( iF );
4179 // find source edge of a free face iF
4180 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4181 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4182 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4183 initNodeSet.begin(), initNodeSet.end(),
4184 commonNodes.begin());
4185 if ( (*v)->IsQuadratic() )
4186 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4188 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4190 if ( !srcEdges.back() )
4192 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4193 << iF << " of volume #" << vTool.ID() << endl;
4198 if ( freeInd.empty() )
4201 // create faces for all steps;
4202 // if such a face has been already created by sweep of edge,
4203 // assure that its orientation is OK
4204 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4205 vTool.Set( *v, /*ignoreCentralNodes=*/false );
4206 vTool.SetExternalNormal();
4207 const int nextShift = vTool.IsForward() ? +1 : -1;
4208 list< int >::iterator ind = freeInd.begin();
4209 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4210 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4212 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4213 int nbn = vTool.NbFaceNodes( *ind );
4214 const SMDS_MeshElement * f = 0;
4215 if ( nbn == 3 ) ///// triangle
4217 f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4219 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4221 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4223 nodes[ 1 + nextShift ] };
4225 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4227 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4231 else if ( nbn == 4 ) ///// quadrangle
4233 f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4235 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4237 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4238 nodes[ 2 ], nodes[ 2+nextShift ] };
4240 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4242 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4243 newOrder[ 2 ], newOrder[ 3 ]));
4246 else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4248 f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4250 nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4252 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4254 nodes[2 + 2*nextShift],
4255 nodes[3 - 2*nextShift],
4257 nodes[3 + 2*nextShift]};
4259 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4261 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4269 else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4271 f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4272 nodes[1], nodes[3], nodes[5], nodes[7] );
4274 nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4276 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4277 nodes[4 - 2*nextShift],
4279 nodes[4 + 2*nextShift],
4281 nodes[5 - 2*nextShift],
4283 nodes[5 + 2*nextShift] };
4285 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4287 myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4288 newOrder[ 2 ], newOrder[ 3 ],
4289 newOrder[ 4 ], newOrder[ 5 ],
4290 newOrder[ 6 ], newOrder[ 7 ]));
4293 else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4295 f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4296 SMDSAbs_Face, /*noMedium=*/false);
4298 nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4300 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4301 nodes[4 - 2*nextShift],
4303 nodes[4 + 2*nextShift],
4305 nodes[5 - 2*nextShift],
4307 nodes[5 + 2*nextShift],
4310 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4312 myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4313 newOrder[ 2 ], newOrder[ 3 ],
4314 newOrder[ 4 ], newOrder[ 5 ],
4315 newOrder[ 6 ], newOrder[ 7 ],
4319 else //////// polygon
4321 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4322 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4324 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4326 if ( !vTool.IsForward() )
4327 std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4329 aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4331 AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4335 while ( srcElements.Length() < myLastCreatedElems.Length() )
4336 srcElements.Append( *srcEdge );
4338 } // loop on free faces
4340 // go to the next volume
4342 while ( iVol++ < nbVolumesByStep ) v++;
4345 } // loop on volumes of one step
4346 } // sweep free links into faces
4348 // Make a ceiling face with a normal external to a volume
4350 SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4352 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4354 lastVol.SetExternalNormal();
4355 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4356 int nbn = lastVol.NbFaceNodes( iF );
4358 if (!hasFreeLinks ||
4359 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4360 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4362 else if ( nbn == 4 )
4364 if (!hasFreeLinks ||
4365 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4366 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4368 else if ( nbn == 6 && isQuadratic )
4370 if (!hasFreeLinks ||
4371 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4372 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4373 nodes[1], nodes[3], nodes[5]));
4375 else if ( nbn == 8 && isQuadratic )
4377 if (!hasFreeLinks ||
4378 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4379 nodes[1], nodes[3], nodes[5], nodes[7]) )
4380 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4381 nodes[1], nodes[3], nodes[5], nodes[7]));
4383 else if ( nbn == 9 && isQuadratic )
4385 if (!hasFreeLinks ||
4386 !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4387 SMDSAbs_Face, /*noMedium=*/false) )
4388 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4389 nodes[1], nodes[3], nodes[5], nodes[7],
4393 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4394 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4395 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4398 while ( srcElements.Length() < myLastCreatedElems.Length() )
4399 srcElements.Append( myLastCreatedElems.Last() );
4401 } // loop on swept elements
4404 //=======================================================================
4405 //function : RotationSweep
4407 //=======================================================================
4409 SMESH_MeshEditor::PGroupIDs
4410 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4411 const gp_Ax1& theAxis,
4412 const double theAngle,
4413 const int theNbSteps,
4414 const double theTol,
4415 const bool theMakeGroups,
4416 const bool theMakeWalls)
4418 myLastCreatedElems.Clear();
4419 myLastCreatedNodes.Clear();
4421 // source elements for each generated one
4422 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4424 MESSAGE( "RotationSweep()");
4426 aTrsf.SetRotation( theAxis, theAngle );
4428 aTrsf2.SetRotation( theAxis, theAngle/2. );
4430 gp_Lin aLine( theAxis );
4431 double aSqTol = theTol * theTol;
4433 SMESHDS_Mesh* aMesh = GetMeshDS();
4435 TNodeOfNodeListMap mapNewNodes;
4436 TElemOfVecOfNnlmiMap mapElemNewNodes;
4437 TElemOfElemListMap newElemsMap;
4439 const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4440 myMesh->NbFaces(ORDER_QUADRATIC) +
4441 myMesh->NbVolumes(ORDER_QUADRATIC) );
4443 TIDSortedElemSet::iterator itElem;
4444 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4445 const SMDS_MeshElement* elem = *itElem;
4446 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4448 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4449 newNodesItVec.reserve( elem->NbNodes() );
4451 // loop on elem nodes
4452 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4453 while ( itN->more() )
4455 // check if a node has been already sweeped
4456 const SMDS_MeshNode* node = cast2Node( itN->next() );
4458 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4460 aXYZ.Coord( coord[0], coord[1], coord[2] );
4461 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4463 TNodeOfNodeListMapItr nIt =
4464 mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4465 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4466 if ( listNewNodes.empty() )
4468 // check if we are to create medium nodes between corner ones
4469 bool needMediumNodes = false;
4470 if ( isQuadraticMesh )
4472 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4473 while (it->more() && !needMediumNodes )
4475 const SMDS_MeshElement* invElem = it->next();
4476 if ( invElem != elem && !theElems.count( invElem )) continue;
4477 needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4478 if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4479 needMediumNodes = true;
4484 const SMDS_MeshNode * newNode = node;
4485 for ( int i = 0; i < theNbSteps; i++ ) {
4487 if ( needMediumNodes ) // create a medium node
4489 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4490 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4491 myLastCreatedNodes.Append(newNode);
4492 srcNodes.Append( node );
4493 listNewNodes.push_back( newNode );
4494 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4497 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4499 // create a corner node
4500 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4501 myLastCreatedNodes.Append(newNode);
4502 srcNodes.Append( node );
4503 listNewNodes.push_back( newNode );
4506 listNewNodes.push_back( newNode );
4507 // if ( needMediumNodes )
4508 // listNewNodes.push_back( newNode );
4512 newNodesItVec.push_back( nIt );
4514 // make new elements
4515 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4519 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4521 PGroupIDs newGroupIDs;
4522 if ( theMakeGroups )
4523 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4529 //=======================================================================
4530 //function : CreateNode
4532 //=======================================================================
4533 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4536 const double tolnode,
4537 SMESH_SequenceOfNode& aNodes)
4539 // myLastCreatedElems.Clear();
4540 // myLastCreatedNodes.Clear();
4543 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4545 // try to search in sequence of existing nodes
4546 // if aNodes.Length()>0 we 'nave to use given sequence
4547 // else - use all nodes of mesh
4548 if(aNodes.Length()>0) {
4550 for(i=1; i<=aNodes.Length(); i++) {
4551 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4552 if(P1.Distance(P2)<tolnode)
4553 return aNodes.Value(i);
4557 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4558 while(itn->more()) {
4559 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4560 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4561 if(P1.Distance(P2)<tolnode)
4566 // create new node and return it
4567 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4568 //myLastCreatedNodes.Append(NewNode);
4573 //=======================================================================
4574 //function : ExtrusionSweep
4576 //=======================================================================
4578 SMESH_MeshEditor::PGroupIDs
4579 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4580 const gp_Vec& theStep,
4581 const int theNbSteps,
4582 TElemOfElemListMap& newElemsMap,
4583 const bool theMakeGroups,
4585 const double theTolerance)
4587 ExtrusParam aParams;
4588 aParams.myDir = gp_Dir(theStep);
4589 aParams.myNodes.Clear();
4590 aParams.mySteps = new TColStd_HSequenceOfReal;
4592 for(i=1; i<=theNbSteps; i++)
4593 aParams.mySteps->Append(theStep.Magnitude());
4596 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4600 //=======================================================================
4601 //function : ExtrusionSweep
4603 //=======================================================================
4605 SMESH_MeshEditor::PGroupIDs
4606 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4607 ExtrusParam& theParams,
4608 TElemOfElemListMap& newElemsMap,
4609 const bool theMakeGroups,
4611 const double theTolerance)
4613 myLastCreatedElems.Clear();
4614 myLastCreatedNodes.Clear();
4616 // source elements for each generated one
4617 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4619 SMESHDS_Mesh* aMesh = GetMeshDS();
4621 int nbsteps = theParams.mySteps->Length();
4623 TNodeOfNodeListMap mapNewNodes;
4624 //TNodeOfNodeVecMap mapNewNodes;
4625 TElemOfVecOfNnlmiMap mapElemNewNodes;
4626 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4628 const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4629 myMesh->NbFaces(ORDER_QUADRATIC) +
4630 myMesh->NbVolumes(ORDER_QUADRATIC) );
4632 TIDSortedElemSet::iterator itElem;
4633 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4634 // check element type
4635 const SMDS_MeshElement* elem = *itElem;
4636 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4639 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4640 newNodesItVec.reserve( elem->NbNodes() );
4642 // loop on elem nodes
4643 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4644 while ( itN->more() )
4646 // check if a node has been already sweeped
4647 const SMDS_MeshNode* node = cast2Node( itN->next() );
4648 TNodeOfNodeListMap::iterator nIt =
4649 mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4650 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4651 if ( listNewNodes.empty() )
4655 // check if we are to create medium nodes between corner ones
4656 bool needMediumNodes = false;
4657 if ( isQuadraticMesh )
4659 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4660 while (it->more() && !needMediumNodes )
4662 const SMDS_MeshElement* invElem = it->next();
4663 if ( invElem != elem && !theElems.count( invElem )) continue;
4664 needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4665 if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4666 needMediumNodes = true;
4670 double coord[] = { node->X(), node->Y(), node->Z() };
4671 for ( int i = 0; i < nbsteps; i++ )
4673 if ( needMediumNodes ) // create a medium node
4675 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4676 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4677 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4678 if( theFlags & EXTRUSION_FLAG_SEW ) {
4679 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4680 theTolerance, theParams.myNodes);
4681 listNewNodes.push_back( newNode );
4684 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4685 myLastCreatedNodes.Append(newNode);
4686 srcNodes.Append( node );
4687 listNewNodes.push_back( newNode );
4690 // create a corner node
4691 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4692 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4693 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4694 if( theFlags & EXTRUSION_FLAG_SEW ) {
4695 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4696 theTolerance, theParams.myNodes);
4697 listNewNodes.push_back( newNode );
4700 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4701 myLastCreatedNodes.Append(newNode);
4702 srcNodes.Append( node );
4703 listNewNodes.push_back( newNode );
4707 newNodesItVec.push_back( nIt );
4709 // make new elements
4710 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4713 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4714 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4716 PGroupIDs newGroupIDs;
4717 if ( theMakeGroups )
4718 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4723 //=======================================================================
4724 //function : ExtrusionAlongTrack
4726 //=======================================================================
4727 SMESH_MeshEditor::Extrusion_Error
4728 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4729 SMESH_subMesh* theTrack,
4730 const SMDS_MeshNode* theN1,
4731 const bool theHasAngles,
4732 list<double>& theAngles,
4733 const bool theLinearVariation,
4734 const bool theHasRefPoint,
4735 const gp_Pnt& theRefPoint,
4736 const bool theMakeGroups)
4738 MESSAGE("ExtrusionAlongTrack");
4739 myLastCreatedElems.Clear();
4740 myLastCreatedNodes.Clear();
4743 std::list<double> aPrms;
4744 TIDSortedElemSet::iterator itElem;
4747 TopoDS_Edge aTrackEdge;
4748 TopoDS_Vertex aV1, aV2;
4750 SMDS_ElemIteratorPtr aItE;
4751 SMDS_NodeIteratorPtr aItN;
4752 SMDSAbs_ElementType aTypeE;
4754 TNodeOfNodeListMap mapNewNodes;
4757 aNbE = theElements.size();
4760 return EXTR_NO_ELEMENTS;
4762 // 1.1 Track Pattern
4765 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4767 aItE = pSubMeshDS->GetElements();
4768 while ( aItE->more() ) {
4769 const SMDS_MeshElement* pE = aItE->next();
4770 aTypeE = pE->GetType();
4771 // Pattern must contain links only
4772 if ( aTypeE != SMDSAbs_Edge )
4773 return EXTR_PATH_NOT_EDGE;
4776 list<SMESH_MeshEditor_PathPoint> fullList;
4778 const TopoDS_Shape& aS = theTrack->GetSubShape();
4779 // Sub-shape for the Pattern must be an Edge or Wire
4780 if( aS.ShapeType() == TopAbs_EDGE ) {
4781 aTrackEdge = TopoDS::Edge( aS );
4782 // the Edge must not be degenerated
4783 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4784 return EXTR_BAD_PATH_SHAPE;
4785 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4786 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4787 const SMDS_MeshNode* aN1 = aItN->next();
4788 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4789 const SMDS_MeshNode* aN2 = aItN->next();
4790 // starting node must be aN1 or aN2
4791 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4792 return EXTR_BAD_STARTING_NODE;
4793 aItN = pSubMeshDS->GetNodes();
4794 while ( aItN->more() ) {
4795 const SMDS_MeshNode* pNode = aItN->next();
4796 const SMDS_EdgePosition* pEPos =
4797 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4798 double aT = pEPos->GetUParameter();
4799 aPrms.push_back( aT );
4801 //Extrusion_Error err =
4802 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4803 } else if( aS.ShapeType() == TopAbs_WIRE ) {
4804 list< SMESH_subMesh* > LSM;
4805 TopTools_SequenceOfShape Edges;
4806 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4807 while(itSM->more()) {
4808 SMESH_subMesh* SM = itSM->next();
4810 const TopoDS_Shape& aS = SM->GetSubShape();
4813 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4814 int startNid = theN1->GetID();
4815 TColStd_MapOfInteger UsedNums;
4817 int NbEdges = Edges.Length();
4819 for(; i<=NbEdges; i++) {
4821 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4822 for(; itLSM!=LSM.end(); itLSM++) {
4824 if(UsedNums.Contains(k)) continue;
4825 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4826 SMESH_subMesh* locTrack = *itLSM;
4827 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4828 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4829 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4830 const SMDS_MeshNode* aN1 = aItN->next();
4831 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4832 const SMDS_MeshNode* aN2 = aItN->next();
4833 // starting node must be aN1 or aN2
4834 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4835 // 2. Collect parameters on the track edge
4837 aItN = locMeshDS->GetNodes();
4838 while ( aItN->more() ) {
4839 const SMDS_MeshNode* pNode = aItN->next();
4840 const SMDS_EdgePosition* pEPos =
4841 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4842 double aT = pEPos->GetUParameter();
4843 aPrms.push_back( aT );
4845 list<SMESH_MeshEditor_PathPoint> LPP;
4846 //Extrusion_Error err =
4847 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4848 LLPPs.push_back(LPP);
4850 // update startN for search following egde
4851 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4852 else startNid = aN1->GetID();
4856 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4857 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4858 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4859 for(; itPP!=firstList.end(); itPP++) {
4860 fullList.push_back( *itPP );
4862 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4863 fullList.pop_back();
4865 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4866 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4867 itPP = currList.begin();
4868 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4869 gp_Dir D1 = PP1.Tangent();
4870 gp_Dir D2 = PP2.Tangent();
4871 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4872 (D1.Z()+D2.Z())/2 ) );
4873 PP1.SetTangent(Dnew);
4874 fullList.push_back(PP1);
4876 for(; itPP!=firstList.end(); itPP++) {
4877 fullList.push_back( *itPP );
4879 PP1 = fullList.back();
4880 fullList.pop_back();
4882 // if wire not closed
4883 fullList.push_back(PP1);
4887 return EXTR_BAD_PATH_SHAPE;
4890 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4891 theHasRefPoint, theRefPoint, theMakeGroups);
4895 //=======================================================================
4896 //function : ExtrusionAlongTrack
4898 //=======================================================================
4899 SMESH_MeshEditor::Extrusion_Error
4900 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4901 SMESH_Mesh* theTrack,
4902 const SMDS_MeshNode* theN1,
4903 const bool theHasAngles,
4904 list<double>& theAngles,
4905 const bool theLinearVariation,
4906 const bool theHasRefPoint,
4907 const gp_Pnt& theRefPoint,
4908 const bool theMakeGroups)
4910 myLastCreatedElems.Clear();
4911 myLastCreatedNodes.Clear();
4914 std::list<double> aPrms;
4915 TIDSortedElemSet::iterator itElem;
4918 TopoDS_Edge aTrackEdge;
4919 TopoDS_Vertex aV1, aV2;
4921 SMDS_ElemIteratorPtr aItE;
4922 SMDS_NodeIteratorPtr aItN;
4923 SMDSAbs_ElementType aTypeE;
4925 TNodeOfNodeListMap mapNewNodes;
4928 aNbE = theElements.size();
4931 return EXTR_NO_ELEMENTS;
4933 // 1.1 Track Pattern
4936 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4938 aItE = pMeshDS->elementsIterator();
4939 while ( aItE->more() ) {
4940 const SMDS_MeshElement* pE = aItE->next();
4941 aTypeE = pE->GetType();
4942 // Pattern must contain links only
4943 if ( aTypeE != SMDSAbs_Edge )
4944 return EXTR_PATH_NOT_EDGE;
4947 list<SMESH_MeshEditor_PathPoint> fullList;
4949 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4951 if( aS == SMESH_Mesh::PseudoShape() ) {
4952 //Mesh without shape
4953 const SMDS_MeshNode* currentNode = NULL;
4954 const SMDS_MeshNode* prevNode = theN1;
4955 std::vector<const SMDS_MeshNode*> aNodesList;
4956 aNodesList.push_back(theN1);
4957 int nbEdges = 0, conn=0;
4958 const SMDS_MeshElement* prevElem = NULL;
4959 const SMDS_MeshElement* currentElem = NULL;
4960 int totalNbEdges = theTrack->NbEdges();
4961 SMDS_ElemIteratorPtr nIt;
4964 if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4965 return EXTR_BAD_STARTING_NODE;
4968 conn = nbEdgeConnectivity(theN1);
4970 return EXTR_PATH_NOT_EDGE;
4972 aItE = theN1->GetInverseElementIterator();
4973 prevElem = aItE->next();
4974 currentElem = prevElem;
4976 if(totalNbEdges == 1 ) {
4977 nIt = currentElem->nodesIterator();
4978 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4979 if(currentNode == prevNode)
4980 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4981 aNodesList.push_back(currentNode);
4983 nIt = currentElem->nodesIterator();
4984 while( nIt->more() ) {
4985 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4986 if(currentNode == prevNode)
4987 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4988 aNodesList.push_back(currentNode);
4990 //case of the closed mesh
4991 if(currentNode == theN1) {
4996 conn = nbEdgeConnectivity(currentNode);
4998 return EXTR_PATH_NOT_EDGE;
4999 }else if( conn == 1 && nbEdges > 0 ) {
5004 prevNode = currentNode;
5005 aItE = currentNode->GetInverseElementIterator();
5006 currentElem = aItE->next();
5007 if( currentElem == prevElem)
5008 currentElem = aItE->next();
5009 nIt = currentElem->nodesIterator();
5010 prevElem = currentElem;
5016 if(nbEdges != totalNbEdges)
5017 return EXTR_PATH_NOT_EDGE;
5019 TopTools_SequenceOfShape Edges;
5020 double x1,x2,y1,y2,z1,z2;
5021 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5022 int startNid = theN1->GetID();
5023 for(int i = 1; i < aNodesList.size(); i++) {
5024 x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5025 y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5026 z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5027 TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5028 list<SMESH_MeshEditor_PathPoint> LPP;
5030 MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5031 LLPPs.push_back(LPP);
5032 if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5033 else startNid = aNodesList[i-1]->GetID();
5037 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5038 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5039 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5040 for(; itPP!=firstList.end(); itPP++) {
5041 fullList.push_back( *itPP );
5044 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5045 SMESH_MeshEditor_PathPoint PP2;
5046 fullList.pop_back();
5048 for(; itLLPP!=LLPPs.end(); itLLPP++) {
5049 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5050 itPP = currList.begin();
5051 PP2 = currList.front();
5052 gp_Dir D1 = PP1.Tangent();
5053 gp_Dir D2 = PP2.Tangent();
5054 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5055 (D1.Z()+D2.Z())/2 ) );
5056 PP1.SetTangent(Dnew);
5057 fullList.push_back(PP1);
5059 for(; itPP!=currList.end(); itPP++) {
5060 fullList.push_back( *itPP );
5062 PP1 = fullList.back();
5063 fullList.pop_back();
5065 fullList.push_back(PP1);
5067 } // Sub-shape for the Pattern must be an Edge or Wire
5068 else if( aS.ShapeType() == TopAbs_EDGE ) {
5069 aTrackEdge = TopoDS::Edge( aS );
5070 // the Edge must not be degenerated
5071 if ( BRep_Tool::Degenerated( aTrackEdge ) )
5072 return EXTR_BAD_PATH_SHAPE;
5073 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5074 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5075 const SMDS_MeshNode* aN1 = aItN->next();
5076 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5077 const SMDS_MeshNode* aN2 = aItN->next();
5078 // starting node must be aN1 or aN2
5079 if ( !( aN1 == theN1 || aN2 == theN1 ) )
5080 return EXTR_BAD_STARTING_NODE;
5081 aItN = pMeshDS->nodesIterator();
5082 while ( aItN->more() ) {
5083 const SMDS_MeshNode* pNode = aItN->next();
5084 if( pNode==aN1 || pNode==aN2 ) continue;
5085 const SMDS_EdgePosition* pEPos =
5086 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5087 double aT = pEPos->GetUParameter();
5088 aPrms.push_back( aT );
5090 //Extrusion_Error err =
5091 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5093 else if( aS.ShapeType() == TopAbs_WIRE ) {
5094 list< SMESH_subMesh* > LSM;
5095 TopTools_SequenceOfShape Edges;
5096 TopExp_Explorer eExp(aS, TopAbs_EDGE);
5097 for(; eExp.More(); eExp.Next()) {
5098 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5099 if( BRep_Tool::Degenerated(E) ) continue;
5100 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5106 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5107 int startNid = theN1->GetID();
5108 TColStd_MapOfInteger UsedNums;
5109 int NbEdges = Edges.Length();
5111 for(; i<=NbEdges; i++) {
5113 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5114 for(; itLSM!=LSM.end(); itLSM++) {
5116 if(UsedNums.Contains(k)) continue;
5117 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5118 SMESH_subMesh* locTrack = *itLSM;
5119 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5120 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5121 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5122 const SMDS_MeshNode* aN1 = aItN->next();
5123 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5124 const SMDS_MeshNode* aN2 = aItN->next();
5125 // starting node must be aN1 or aN2
5126 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5127 // 2. Collect parameters on the track edge
5129 aItN = locMeshDS->GetNodes();
5130 while ( aItN->more() ) {
5131 const SMDS_MeshNode* pNode = aItN->next();
5132 const SMDS_EdgePosition* pEPos =
5133 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5134 double aT = pEPos->GetUParameter();
5135 aPrms.push_back( aT );
5137 list<SMESH_MeshEditor_PathPoint> LPP;
5138 //Extrusion_Error err =
5139 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5140 LLPPs.push_back(LPP);
5142 // update startN for search following egde
5143 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5144 else startNid = aN1->GetID();
5148 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5149 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5150 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5151 for(; itPP!=firstList.end(); itPP++) {
5152 fullList.push_back( *itPP );
5154 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5155 fullList.pop_back();
5157 for(; itLLPP!=LLPPs.end(); itLLPP++) {
5158 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5159 itPP = currList.begin();
5160 SMESH_MeshEditor_PathPoint PP2 = currList.front();
5161 gp_Dir D1 = PP1.Tangent();
5162 gp_Dir D2 = PP2.Tangent();
5163 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5164 (D1.Z()+D2.Z())/2 ) );
5165 PP1.SetTangent(Dnew);
5166 fullList.push_back(PP1);
5168 for(; itPP!=currList.end(); itPP++) {
5169 fullList.push_back( *itPP );
5171 PP1 = fullList.back();
5172 fullList.pop_back();
5174 // if wire not closed
5175 fullList.push_back(PP1);
5179 return EXTR_BAD_PATH_SHAPE;
5182 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5183 theHasRefPoint, theRefPoint, theMakeGroups);
5187 //=======================================================================
5188 //function : MakeEdgePathPoints
5189 //purpose : auxilary for ExtrusionAlongTrack
5190 //=======================================================================
5191 SMESH_MeshEditor::Extrusion_Error
5192 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5193 const TopoDS_Edge& aTrackEdge,
5195 list<SMESH_MeshEditor_PathPoint>& LPP)
5197 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5199 aTolVec2=aTolVec*aTolVec;
5201 TopoDS_Vertex aV1, aV2;
5202 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5203 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5204 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5205 // 2. Collect parameters on the track edge
5206 aPrms.push_front( aT1 );
5207 aPrms.push_back( aT2 );
5210 if( FirstIsStart ) {
5221 SMESH_MeshEditor_PathPoint aPP;
5222 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5223 std::list<double>::iterator aItD = aPrms.begin();
5224 for(; aItD != aPrms.end(); ++aItD) {
5228 aC3D->D1( aT, aP3D, aVec );
5229 aL2 = aVec.SquareMagnitude();
5230 if ( aL2 < aTolVec2 )
5231 return EXTR_CANT_GET_TANGENT;
5232 gp_Dir aTgt( aVec );
5234 aPP.SetTangent( aTgt );
5235 aPP.SetParameter( aT );
5242 //=======================================================================
5243 //function : MakeExtrElements
5244 //purpose : auxilary for ExtrusionAlongTrack
5245 //=======================================================================
5246 SMESH_MeshEditor::Extrusion_Error
5247 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5248 list<SMESH_MeshEditor_PathPoint>& fullList,
5249 const bool theHasAngles,
5250 list<double>& theAngles,
5251 const bool theLinearVariation,
5252 const bool theHasRefPoint,
5253 const gp_Pnt& theRefPoint,
5254 const bool theMakeGroups)
5256 MESSAGE("MakeExtrElements");
5257 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5258 int aNbTP = fullList.size();
5259 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5261 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5262 LinearAngleVariation(aNbTP-1, theAngles);
5264 vector<double> aAngles( aNbTP );
5266 for(; j<aNbTP; ++j) {
5269 if ( theHasAngles ) {
5271 std::list<double>::iterator aItD = theAngles.begin();
5272 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5274 aAngles[j] = anAngle;
5277 // fill vector of path points with angles
5278 //aPPs.resize(fullList.size());
5280 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5281 for(; itPP!=fullList.end(); itPP++) {
5283 SMESH_MeshEditor_PathPoint PP = *itPP;
5284 PP.SetAngle(aAngles[j]);
5288 TNodeOfNodeListMap mapNewNodes;
5289 TElemOfVecOfNnlmiMap mapElemNewNodes;
5290 TElemOfElemListMap newElemsMap;
5291 TIDSortedElemSet::iterator itElem;
5294 SMDSAbs_ElementType aTypeE;
5295 // source elements for each generated one
5296 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5298 // 3. Center of rotation aV0
5299 gp_Pnt aV0 = theRefPoint;
5301 if ( !theHasRefPoint ) {
5303 aGC.SetCoord( 0.,0.,0. );
5305 itElem = theElements.begin();
5306 for ( ; itElem != theElements.end(); itElem++ ) {
5307 const SMDS_MeshElement* elem = *itElem;
5309 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5310 while ( itN->more() ) {
5311 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5316 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5317 list<const SMDS_MeshNode*> aLNx;
5318 mapNewNodes[node] = aLNx;
5320 gp_XYZ aXYZ( aX, aY, aZ );
5328 } // if (!theHasRefPoint) {
5329 mapNewNodes.clear();
5331 // 4. Processing the elements
5332 SMESHDS_Mesh* aMesh = GetMeshDS();
5334 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5335 // check element type
5336 const SMDS_MeshElement* elem = *itElem;
5337 aTypeE = elem->GetType();
5338 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5341 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5342 newNodesItVec.reserve( elem->NbNodes() );
5344 // loop on elem nodes
5346 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5347 while ( itN->more() )
5350 // check if a node has been already processed
5351 const SMDS_MeshNode* node =
5352 static_cast<const SMDS_MeshNode*>( itN->next() );
5353 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5354 if ( nIt == mapNewNodes.end() ) {
5355 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5356 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5359 aX = node->X(); aY = node->Y(); aZ = node->Z();
5361 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5362 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5363 gp_Ax1 anAx1, anAxT1T0;
5364 gp_Dir aDT1x, aDT0x, aDT1T0;
5369 aPN0.SetCoord(aX, aY, aZ);
5371 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5373 aDT0x= aPP0.Tangent();
5374 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5376 for ( j = 1; j < aNbTP; ++j ) {
5377 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5379 aDT1x = aPP1.Tangent();
5380 aAngle1x = aPP1.Angle();
5382 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5384 gp_Vec aV01x( aP0x, aP1x );
5385 aTrsf.SetTranslation( aV01x );
5388 aV1x = aV0x.Transformed( aTrsf );
5389 aPN1 = aPN0.Transformed( aTrsf );
5391 // rotation 1 [ T1,T0 ]
5392 aAngleT1T0=-aDT1x.Angle( aDT0x );
5393 if (fabs(aAngleT1T0) > aTolAng) {
5395 anAxT1T0.SetLocation( aV1x );
5396 anAxT1T0.SetDirection( aDT1T0 );
5397 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5399 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5403 if ( theHasAngles ) {
5404 anAx1.SetLocation( aV1x );
5405 anAx1.SetDirection( aDT1x );
5406 aTrsfRot.SetRotation( anAx1, aAngle1x );
5408 aPN1 = aPN1.Transformed( aTrsfRot );
5412 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5413 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5414 // create additional node
5415 double x = ( aPN1.X() + aPN0.X() )/2.;
5416 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5417 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5418 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5419 myLastCreatedNodes.Append(newNode);
5420 srcNodes.Append( node );
5421 listNewNodes.push_back( newNode );
5426 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5427 myLastCreatedNodes.Append(newNode);
5428 srcNodes.Append( node );
5429 listNewNodes.push_back( newNode );
5439 // if current elem is quadratic and current node is not medium
5440 // we have to check - may be it is needed to insert additional nodes
5441 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5442 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5443 if(listNewNodes.size()==aNbTP-1) {
5444 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5445 gp_XYZ P(node->X(), node->Y(), node->Z());
5446 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5448 for(i=0; i<aNbTP-1; i++) {
5449 const SMDS_MeshNode* N = *it;
5450 double x = ( N->X() + P.X() )/2.;
5451 double y = ( N->Y() + P.Y() )/2.;
5452 double z = ( N->Z() + P.Z() )/2.;
5453 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5454 srcNodes.Append( node );
5455 myLastCreatedNodes.Append(newN);
5458 P = gp_XYZ(N->X(),N->Y(),N->Z());
5460 listNewNodes.clear();
5461 for(i=0; i<2*(aNbTP-1); i++) {
5462 listNewNodes.push_back(aNodes[i]);
5468 newNodesItVec.push_back( nIt );
5470 // make new elements
5471 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5472 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5473 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5476 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5478 if ( theMakeGroups )
5479 generateGroups( srcNodes, srcElems, "extruded");
5485 //=======================================================================
5486 //function : LinearAngleVariation
5487 //purpose : auxilary for ExtrusionAlongTrack
5488 //=======================================================================
5489 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5490 list<double>& Angles)
5492 int nbAngles = Angles.size();
5493 if( nbSteps > nbAngles ) {
5494 vector<double> theAngles(nbAngles);
5495 list<double>::iterator it = Angles.begin();
5497 for(; it!=Angles.end(); it++) {
5499 theAngles[i] = (*it);
5502 double rAn2St = double( nbAngles ) / double( nbSteps );
5503 double angPrev = 0, angle;
5504 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5505 double angCur = rAn2St * ( iSt+1 );
5506 double angCurFloor = floor( angCur );
5507 double angPrevFloor = floor( angPrev );
5508 if ( angPrevFloor == angCurFloor )
5509 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5511 int iP = int( angPrevFloor );
5512 double angPrevCeil = ceil(angPrev);
5513 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5515 int iC = int( angCurFloor );
5516 if ( iC < nbAngles )
5517 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5519 iP = int( angPrevCeil );
5521 angle += theAngles[ iC ];
5523 res.push_back(angle);
5528 for(; it!=res.end(); it++)
5529 Angles.push_back( *it );
5534 //================================================================================
5536 * \brief Move or copy theElements applying theTrsf to their nodes
5537 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5538 * \param theTrsf - transformation to apply
5539 * \param theCopy - if true, create translated copies of theElems
5540 * \param theMakeGroups - if true and theCopy, create translated groups
5541 * \param theTargetMesh - mesh to copy translated elements into
5542 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5544 //================================================================================
5546 SMESH_MeshEditor::PGroupIDs
5547 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5548 const gp_Trsf& theTrsf,
5550 const bool theMakeGroups,
5551 SMESH_Mesh* theTargetMesh)
5553 myLastCreatedElems.Clear();
5554 myLastCreatedNodes.Clear();
5556 bool needReverse = false;
5557 string groupPostfix;
5558 switch ( theTrsf.Form() ) {
5560 MESSAGE("gp_PntMirror");
5562 groupPostfix = "mirrored";
5565 MESSAGE("gp_Ax1Mirror");
5566 groupPostfix = "mirrored";
5569 MESSAGE("gp_Ax2Mirror");
5571 groupPostfix = "mirrored";
5574 MESSAGE("gp_Rotation");
5575 groupPostfix = "rotated";
5577 case gp_Translation:
5578 MESSAGE("gp_Translation");
5579 groupPostfix = "translated";
5582 MESSAGE("gp_Scale");
5583 groupPostfix = "scaled";
5585 case gp_CompoundTrsf: // different scale by axis
5586 MESSAGE("gp_CompoundTrsf");
5587 groupPostfix = "scaled";
5591 needReverse = false;
5592 groupPostfix = "transformed";
5595 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5596 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5597 SMESHDS_Mesh* aMesh = GetMeshDS();
5600 // map old node to new one
5601 TNodeNodeMap nodeMap;
5603 // elements sharing moved nodes; those of them which have all
5604 // nodes mirrored but are not in theElems are to be reversed
5605 TIDSortedElemSet inverseElemSet;
5607 // source elements for each generated one
5608 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5610 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5611 TIDSortedElemSet orphanNode;
5613 if ( theElems.empty() ) // transform the whole mesh
5616 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5617 while ( eIt->more() ) theElems.insert( eIt->next() );
5619 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5620 while ( nIt->more() )
5622 const SMDS_MeshNode* node = nIt->next();
5623 if ( node->NbInverseElements() == 0)
5624 orphanNode.insert( node );
5628 // loop on elements to transform nodes : first orphan nodes then elems
5629 TIDSortedElemSet::iterator itElem;
5630 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5631 for (int i=0; i<2; i++)
5632 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5633 const SMDS_MeshElement* elem = *itElem;
5637 // loop on elem nodes
5638 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5639 while ( itN->more() ) {
5641 const SMDS_MeshNode* node = cast2Node( itN->next() );
5642 // check if a node has been already transformed
5643 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5644 nodeMap.insert( make_pair ( node, node ));
5645 if ( !n2n_isnew.second )
5649 coord[0] = node->X();
5650 coord[1] = node->Y();
5651 coord[2] = node->Z();
5652 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5653 if ( theTargetMesh ) {
5654 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5655 n2n_isnew.first->second = newNode;
5656 myLastCreatedNodes.Append(newNode);
5657 srcNodes.Append( node );
5659 else if ( theCopy ) {
5660 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5661 n2n_isnew.first->second = newNode;
5662 myLastCreatedNodes.Append(newNode);
5663 srcNodes.Append( node );
5666 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5667 // node position on shape becomes invalid
5668 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5669 ( SMDS_SpacePosition::originSpacePosition() );
5672 // keep inverse elements
5673 if ( !theCopy && !theTargetMesh && needReverse ) {
5674 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5675 while ( invElemIt->more() ) {
5676 const SMDS_MeshElement* iel = invElemIt->next();
5677 inverseElemSet.insert( iel );
5683 // either create new elements or reverse mirrored ones
5684 if ( !theCopy && !needReverse && !theTargetMesh )
5687 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5688 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5689 theElems.insert( *invElemIt );
5691 // Replicate or reverse elements
5693 std::vector<int> iForw;
5694 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5696 const SMDS_MeshElement* elem = *itElem;
5697 if ( !elem || elem->GetType() == SMDSAbs_Node )
5700 int nbNodes = elem->NbNodes();
5701 int elemType = elem->GetType();
5703 if (elem->IsPoly()) {
5705 // polygon or polyhedral volume
5706 switch ( elemType ) {
5709 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5711 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5712 while (itN->more()) {
5713 const SMDS_MeshNode* node =
5714 static_cast<const SMDS_MeshNode*>(itN->next());
5715 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5716 if (nodeMapIt == nodeMap.end())
5717 break; // not all nodes transformed
5719 // reverse mirrored faces and volumes
5720 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5722 poly_nodes[iNode] = (*nodeMapIt).second;
5726 if ( iNode != nbNodes )
5727 continue; // not all nodes transformed
5729 if ( theTargetMesh ) {
5730 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5731 srcElems.Append( elem );
5733 else if ( theCopy ) {
5734 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5735 srcElems.Append( elem );
5738 aMesh->ChangePolygonNodes(elem, poly_nodes);
5742 case SMDSAbs_Volume:
5744 const SMDS_VtkVolume* aPolyedre =
5745 dynamic_cast<const SMDS_VtkVolume*>( elem );
5747 MESSAGE("Warning: bad volumic element");
5751 vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5752 vector<int> quantities;
5754 bool allTransformed = true;
5755 int nbFaces = aPolyedre->NbFaces();
5756 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5757 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5758 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5759 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5760 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5761 if (nodeMapIt == nodeMap.end()) {
5762 allTransformed = false; // not all nodes transformed
5764 poly_nodes.push_back((*nodeMapIt).second);
5766 if ( needReverse && allTransformed )
5767 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5769 quantities.push_back(nbFaceNodes);
5771 if ( !allTransformed )
5772 continue; // not all nodes transformed
5774 if ( theTargetMesh ) {
5775 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5776 srcElems.Append( elem );
5778 else if ( theCopy ) {
5779 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5780 srcElems.Append( elem );
5783 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5795 while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5796 const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5797 const std::vector<int>& i = needReverse ? iRev : iForw;
5799 // find transformed nodes
5800 vector<const SMDS_MeshNode*> nodes(nbNodes);
5802 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5803 while ( itN->more() ) {
5804 const SMDS_MeshNode* node =
5805 static_cast<const SMDS_MeshNode*>( itN->next() );
5806 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5807 if ( nodeMapIt == nodeMap.end() )
5808 break; // not all nodes transformed
5809 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5811 if ( iNode != nbNodes )
5812 continue; // not all nodes transformed
5814 if ( theTargetMesh ) {
5815 if ( SMDS_MeshElement* copy =
5816 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5817 myLastCreatedElems.Append( copy );
5818 srcElems.Append( elem );
5821 else if ( theCopy ) {
5822 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5823 srcElems.Append( elem );
5826 // reverse element as it was reversed by transformation
5828 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5831 } // loop on elements
5833 PGroupIDs newGroupIDs;
5835 if ( ( theMakeGroups && theCopy ) ||
5836 ( theMakeGroups && theTargetMesh ) )
5837 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5842 //=======================================================================
5844 * \brief Create groups of elements made during transformation
5845 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5846 * \param elemGens - elements making corresponding myLastCreatedElems
5847 * \param postfix - to append to names of new groups
5849 //=======================================================================
5851 SMESH_MeshEditor::PGroupIDs
5852 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5853 const SMESH_SequenceOfElemPtr& elemGens,
5854 const std::string& postfix,
5855 SMESH_Mesh* targetMesh)
5857 PGroupIDs newGroupIDs( new list<int> );
5858 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5860 // Sort existing groups by types and collect their names
5862 // to store an old group and a generated new one
5863 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5864 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5866 set< string > groupNames;
5868 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5869 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5870 while ( groupIt->more() ) {
5871 SMESH_Group * group = groupIt->next();
5872 if ( !group ) continue;
5873 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5874 if ( !groupDS || groupDS->IsEmpty() ) continue;
5875 groupNames.insert( group->GetName() );
5876 groupDS->SetStoreName( group->GetName() );
5877 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5882 // loop on nodes and elements
5883 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5885 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5886 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5887 if ( gens.Length() != elems.Length() )
5888 throw SALOME_Exception(LOCALIZED("invalid args"));
5890 // loop on created elements
5891 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5893 const SMDS_MeshElement* sourceElem = gens( iElem );
5894 if ( !sourceElem ) {
5895 MESSAGE("generateGroups(): NULL source element");
5898 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5899 if ( groupsOldNew.empty() ) {
5900 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5901 ++iElem; // skip all elements made by sourceElem
5904 // collect all elements made by sourceElem
5905 list< const SMDS_MeshElement* > resultElems;
5906 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5907 if ( resElem != sourceElem )
5908 resultElems.push_back( resElem );
5909 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5910 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5911 if ( resElem != sourceElem )
5912 resultElems.push_back( resElem );
5913 // do not generate element groups from node ones
5914 // if ( sourceElem->GetType() == SMDSAbs_Node &&
5915 // elems( iElem )->GetType() != SMDSAbs_Node )
5918 // add resultElems to groups made by ones the sourceElem belongs to
5919 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5920 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5922 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5923 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5925 SMDS_MeshGroup* & newGroup = gOldNew->second;
5926 if ( !newGroup )// create a new group
5929 string name = oldGroup->GetStoreName();
5930 if ( !targetMesh ) {
5934 while ( !groupNames.insert( name ).second ) // name exists
5940 TCollection_AsciiString nbStr(nb+1);
5941 name.resize( name.rfind('_')+1 );
5942 name += nbStr.ToCString();
5949 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5951 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5952 newGroup = & groupDS->SMDSGroup();
5953 newGroupIDs->push_back( id );
5956 // fill in a new group
5957 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5958 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5959 newGroup->Add( *resElemIt );
5962 } // loop on created elements
5963 }// loop on nodes and elements
5968 //================================================================================
5970 * \brief Return list of group of nodes close to each other within theTolerance
5971 * Search among theNodes or in the whole mesh if theNodes is empty using
5972 * an Octree algorithm
5974 //================================================================================
5976 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
5977 const double theTolerance,
5978 TListOfListOfNodes & theGroupsOfNodes)
5980 myLastCreatedElems.Clear();
5981 myLastCreatedNodes.Clear();
5983 if ( theNodes.empty() )
5984 { // get all nodes in the mesh
5985 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5986 while ( nIt->more() )
5987 theNodes.insert( theNodes.end(),nIt->next());
5990 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5994 //=======================================================================
5996 * \brief Implementation of search for the node closest to point
5998 //=======================================================================
6000 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6002 //---------------------------------------------------------------------
6004 * \brief Constructor
6006 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6008 myMesh = ( SMESHDS_Mesh* ) theMesh;
6010 TIDSortedNodeSet nodes;
6012 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6013 while ( nIt->more() )
6014 nodes.insert( nodes.end(), nIt->next() );
6016 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6018 // get max size of a leaf box
6019 SMESH_OctreeNode* tree = myOctreeNode;
6020 while ( !tree->isLeaf() )
6022 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6026 myHalfLeafSize = tree->maxSize() / 2.;
6029 //---------------------------------------------------------------------
6031 * \brief Move node and update myOctreeNode accordingly
6033 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6035 myOctreeNode->UpdateByMoveNode( node, toPnt );
6036 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6039 //---------------------------------------------------------------------
6041 * \brief Do it's job
6043 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6045 map<double, const SMDS_MeshNode*> dist2Nodes;
6046 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6047 if ( !dist2Nodes.empty() )
6048 return dist2Nodes.begin()->second;
6049 list<const SMDS_MeshNode*> nodes;
6050 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6052 double minSqDist = DBL_MAX;
6053 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6055 // sort leafs by their distance from thePnt
6056 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6057 TDistTreeMap treeMap;
6058 list< SMESH_OctreeNode* > treeList;
6059 list< SMESH_OctreeNode* >::iterator trIt;
6060 treeList.push_back( myOctreeNode );
6062 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6063 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6064 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6066 SMESH_OctreeNode* tree = *trIt;
6067 if ( !tree->isLeaf() ) // put children to the queue
6069 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6070 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6071 while ( cIt->more() )
6072 treeList.push_back( cIt->next() );
6074 else if ( tree->NbNodes() ) // put a tree to the treeMap
6076 const Bnd_B3d& box = tree->getBox();
6077 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6078 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6079 if ( !it_in.second ) // not unique distance to box center
6080 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6083 // find distance after which there is no sense to check tree's
6084 double sqLimit = DBL_MAX;
6085 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6086 if ( treeMap.size() > 5 ) {
6087 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6088 const Bnd_B3d& box = closestTree->getBox();
6089 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6090 sqLimit = limit * limit;
6092 // get all nodes from trees
6093 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6094 if ( sqDist_tree->first > sqLimit )
6096 SMESH_OctreeNode* tree = sqDist_tree->second;
6097 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6100 // find closest among nodes
6101 minSqDist = DBL_MAX;
6102 const SMDS_MeshNode* closestNode = 0;
6103 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6104 for ( ; nIt != nodes.end(); ++nIt ) {
6105 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6106 if ( minSqDist > sqDist ) {
6114 //---------------------------------------------------------------------
6118 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6120 //---------------------------------------------------------------------
6122 * \brief Return the node tree
6124 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6127 SMESH_OctreeNode* myOctreeNode;
6128 SMESHDS_Mesh* myMesh;
6129 double myHalfLeafSize; // max size of a leaf box
6132 //=======================================================================
6134 * \brief Return SMESH_NodeSearcher
6136 //=======================================================================
6138 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6140 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6143 // ========================================================================
6144 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6146 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6147 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6148 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6150 //=======================================================================
6152 * \brief Octal tree of bounding boxes of elements
6154 //=======================================================================
6156 class ElementBndBoxTree : public SMESH_Octree
6160 ElementBndBoxTree(const SMDS_Mesh& mesh,
6161 SMDSAbs_ElementType elemType,
6162 SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
6163 double tolerance = NodeRadius );
6164 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
6165 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6166 void getElementsInSphere ( const gp_XYZ& center,
6167 const double radius, TIDSortedElemSet& foundElems);
6168 size_t getSize() { return std::max( _size, _elements.size() ); }
6169 ~ElementBndBoxTree();
6172 ElementBndBoxTree():_size(0) {}
6173 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6174 void buildChildrenData();
6175 Bnd_B3d* buildRootBox();
6177 //!< Bounding box of element
6178 struct ElementBox : public Bnd_B3d
6180 const SMDS_MeshElement* _element;
6181 int _refCount; // an ElementBox can be included in several tree branches
6182 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6184 vector< ElementBox* > _elements;
6188 //================================================================================
6190 * \brief ElementBndBoxTree creation
6192 //================================================================================
6194 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6195 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6197 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6198 _elements.reserve( nbElems );
6200 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6201 while ( elemIt->more() )
6202 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6207 //================================================================================
6211 //================================================================================
6213 ElementBndBoxTree::~ElementBndBoxTree()
6215 for ( int i = 0; i < _elements.size(); ++i )
6216 if ( --_elements[i]->_refCount <= 0 )
6217 delete _elements[i];
6220 //================================================================================
6222 * \brief Return the maximal box
6224 //================================================================================
6226 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6228 Bnd_B3d* box = new Bnd_B3d;
6229 for ( int i = 0; i < _elements.size(); ++i )
6230 box->Add( *_elements[i] );
6234 //================================================================================
6236 * \brief Redistrubute element boxes among children
6238 //================================================================================
6240 void ElementBndBoxTree::buildChildrenData()
6242 for ( int i = 0; i < _elements.size(); ++i )
6244 for (int j = 0; j < 8; j++)
6246 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6248 _elements[i]->_refCount++;
6249 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6252 _elements[i]->_refCount--;
6254 _size = _elements.size();
6255 SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
6257 for (int j = 0; j < 8; j++)
6259 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6260 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6261 child->myIsLeaf = true;
6263 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6264 SMESHUtils::CompactVector( child->_elements );
6268 //================================================================================
6270 * \brief Return elements which can include the point
6272 //================================================================================
6274 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6275 TIDSortedElemSet& foundElems)
6277 if ( getBox().IsOut( point.XYZ() ))
6282 for ( int i = 0; i < _elements.size(); ++i )
6283 if ( !_elements[i]->IsOut( point.XYZ() ))
6284 foundElems.insert( _elements[i]->_element );
6288 for (int i = 0; i < 8; i++)
6289 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6293 //================================================================================
6295 * \brief Return elements which can be intersected by the line
6297 //================================================================================
6299 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6300 TIDSortedElemSet& foundElems)
6302 if ( getBox().IsOut( line ))
6307 for ( int i = 0; i < _elements.size(); ++i )
6308 if ( !_elements[i]->IsOut( line ))
6309 foundElems.insert( _elements[i]->_element );
6313 for (int i = 0; i < 8; i++)
6314 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6318 //================================================================================
6320 * \brief Return elements from leaves intersecting the sphere
6322 //================================================================================
6324 void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center,
6325 const double radius,
6326 TIDSortedElemSet& foundElems)
6328 if ( getBox().IsOut( center, radius ))
6333 for ( int i = 0; i < _elements.size(); ++i )
6334 if ( !_elements[i]->IsOut( center, radius ))
6335 foundElems.insert( _elements[i]->_element );
6339 for (int i = 0; i < 8; i++)
6340 ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
6344 //================================================================================
6346 * \brief Construct the element box
6348 //================================================================================
6350 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6354 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6355 while ( nIt->more() )
6356 Add( SMESH_TNodeXYZ( nIt->next() ));
6357 Enlarge( tolerance );
6362 //=======================================================================
6364 * \brief Implementation of search for the elements by point and
6365 * of classification of point in 2D mesh
6367 //=======================================================================
6369 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6371 SMESHDS_Mesh* _mesh;
6372 SMDS_ElemIteratorPtr _meshPartIt;
6373 ElementBndBoxTree* _ebbTree;
6374 SMESH_NodeSearcherImpl* _nodeSearcher;
6375 SMDSAbs_ElementType _elementType;
6377 bool _outerFacesFound;
6378 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6380 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6381 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6382 ~SMESH_ElementSearcherImpl()
6384 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6385 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6387 virtual int FindElementsByPoint(const gp_Pnt& point,
6388 SMDSAbs_ElementType type,
6389 vector< const SMDS_MeshElement* >& foundElements);
6390 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6391 virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point,
6392 SMDSAbs_ElementType type );
6394 void GetElementsNearLine( const gp_Ax1& line,
6395 SMDSAbs_ElementType type,
6396 vector< const SMDS_MeshElement* >& foundElems);
6397 double getTolerance();
6398 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6399 const double tolerance, double & param);
6400 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6401 bool isOuterBoundary(const SMDS_MeshElement* face) const
6403 return _outerFaces.empty() || _outerFaces.count(face);
6405 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6407 const SMDS_MeshElement* _face;
6409 bool _coincides; //!< the line lays in face plane
6410 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6411 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6413 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6416 TIDSortedElemSet _faces;
6417 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6418 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6422 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6424 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6425 << ", _coincides="<<i._coincides << ")";
6428 //=======================================================================
6430 * \brief define tolerance for search
6432 //=======================================================================
6434 double SMESH_ElementSearcherImpl::getTolerance()
6436 if ( _tolerance < 0 )
6438 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6441 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6443 double boxSize = _nodeSearcher->getTree()->maxSize();
6444 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6446 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6448 double boxSize = _ebbTree->maxSize();
6449 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6451 if ( _tolerance == 0 )
6453 // define tolerance by size of a most complex element
6454 int complexType = SMDSAbs_Volume;
6455 while ( complexType > SMDSAbs_All &&
6456 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6458 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6460 if ( complexType == int( SMDSAbs_Node ))
6462 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6464 if ( meshInfo.NbNodes() > 2 )
6465 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6469 SMDS_ElemIteratorPtr elemIt =
6470 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6471 const SMDS_MeshElement* elem = elemIt->next();
6472 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6473 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6475 while ( nodeIt->more() )
6477 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6478 elemSize = max( dist, elemSize );
6481 _tolerance = 1e-4 * elemSize;
6487 //================================================================================
6489 * \brief Find intersection of the line and an edge of face and return parameter on line
6491 //================================================================================
6493 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6494 const SMDS_MeshElement* face,
6501 GeomAPI_ExtremaCurveCurve anExtCC;
6502 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6504 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6505 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6507 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6508 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6509 anExtCC.Init( lineCurve, edge);
6510 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6512 Quantity_Parameter pl, pe;
6513 anExtCC.LowerDistanceParameters( pl, pe );
6515 if ( ++nbInts == 2 )
6519 if ( nbInts > 0 ) param /= nbInts;
6522 //================================================================================
6524 * \brief Find all faces belonging to the outer boundary of mesh
6526 //================================================================================
6528 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6530 if ( _outerFacesFound ) return;
6532 // Collect all outer faces by passing from one outer face to another via their links
6533 // and BTW find out if there are internal faces at all.
6535 // checked links and links where outer boundary meets internal one
6536 set< SMESH_TLink > visitedLinks, seamLinks;
6538 // links to treat with already visited faces sharing them
6539 list < TFaceLink > startLinks;
6541 // load startLinks with the first outerFace
6542 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6543 _outerFaces.insert( outerFace );
6545 TIDSortedElemSet emptySet;
6546 while ( !startLinks.empty() )
6548 const SMESH_TLink& link = startLinks.front()._link;
6549 TIDSortedElemSet& faces = startLinks.front()._faces;
6551 outerFace = *faces.begin();
6552 // find other faces sharing the link
6553 const SMDS_MeshElement* f;
6554 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6557 // select another outer face among the found
6558 const SMDS_MeshElement* outerFace2 = 0;
6559 if ( faces.size() == 2 )
6561 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6563 else if ( faces.size() > 2 )
6565 seamLinks.insert( link );
6567 // link direction within the outerFace
6568 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6569 SMESH_TNodeXYZ( link.node2()));
6570 int i1 = outerFace->GetNodeIndex( link.node1() );
6571 int i2 = outerFace->GetNodeIndex( link.node2() );
6572 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6573 if ( rev ) n1n2.Reverse();
6575 gp_XYZ ofNorm, fNorm;
6576 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6578 // direction from the link inside outerFace
6579 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6580 // sort all other faces by angle with the dirInOF
6581 map< double, const SMDS_MeshElement* > angle2Face;
6582 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6583 for ( ; face != faces.end(); ++face )
6585 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6587 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6588 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6589 if ( angle < 0 ) angle += 2. * M_PI;
6590 angle2Face.insert( make_pair( angle, *face ));
6592 if ( !angle2Face.empty() )
6593 outerFace2 = angle2Face.begin()->second;
6596 // store the found outer face and add its links to continue seaching from
6599 _outerFaces.insert( outerFace );
6600 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6601 for ( int i = 0; i < nbNodes; ++i )
6603 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6604 if ( visitedLinks.insert( link2 ).second )
6605 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6608 startLinks.pop_front();
6610 _outerFacesFound = true;
6612 if ( !seamLinks.empty() )
6614 // There are internal boundaries touching the outher one,
6615 // find all faces of internal boundaries in order to find
6616 // faces of boundaries of holes, if any.
6621 _outerFaces.clear();
6625 //=======================================================================
6627 * \brief Find elements of given type where the given point is IN or ON.
6628 * Returns nb of found elements and elements them-selves.
6630 * 'ALL' type means elements of any type excluding nodes and 0D elements
6632 //=======================================================================
6634 int SMESH_ElementSearcherImpl::
6635 FindElementsByPoint(const gp_Pnt& point,
6636 SMDSAbs_ElementType type,
6637 vector< const SMDS_MeshElement* >& foundElements)
6639 foundElements.clear();
6641 double tolerance = getTolerance();
6643 // =================================================================================
6644 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6646 if ( !_nodeSearcher )
6647 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6649 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6650 if ( !closeNode ) return foundElements.size();
6652 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6653 return foundElements.size(); // to far from any node
6655 if ( type == SMDSAbs_Node )
6657 foundElements.push_back( closeNode );
6661 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6662 while ( elemIt->more() )
6663 foundElements.push_back( elemIt->next() );
6666 // =================================================================================
6667 else // elements more complex than 0D
6669 if ( !_ebbTree || _elementType != type )
6671 if ( _ebbTree ) delete _ebbTree;
6672 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6674 TIDSortedElemSet suspectElems;
6675 _ebbTree->getElementsNearPoint( point, suspectElems );
6676 TIDSortedElemSet::iterator elem = suspectElems.begin();
6677 for ( ; elem != suspectElems.end(); ++elem )
6678 if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance ))
6679 foundElements.push_back( *elem );
6681 return foundElements.size();
6684 //=======================================================================
6686 * \brief Find an element of given type most close to the given point
6688 * WARNING: Only face search is implemeneted so far
6690 //=======================================================================
6692 const SMDS_MeshElement*
6693 SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point,
6694 SMDSAbs_ElementType type )
6696 const SMDS_MeshElement* closestElem = 0;
6698 if ( type == SMDSAbs_Face )
6700 if ( !_ebbTree || _elementType != type )
6702 if ( _ebbTree ) delete _ebbTree;
6703 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6705 TIDSortedElemSet suspectElems;
6706 _ebbTree->getElementsNearPoint( point, suspectElems );
6708 if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
6710 gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox().CornerMin() +
6711 _ebbTree->getBox().CornerMax() );
6713 if ( _ebbTree->getBox().IsOut( point.XYZ() ))
6714 radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
6716 radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
6717 while ( suspectElems.empty() )
6719 _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
6723 double minDist = std::numeric_limits<double>::max();
6724 multimap< double, const SMDS_MeshElement* > dist2face;
6725 TIDSortedElemSet::iterator elem = suspectElems.begin();
6726 for ( ; elem != suspectElems.end(); ++elem )
6728 double dist = SMESH_MeshEditor::GetDistance( dynamic_cast<const SMDS_MeshFace*>(*elem),
6730 if ( dist < minDist + 1e-10)
6733 dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
6736 if ( !dist2face.empty() )
6738 multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
6739 closestElem = d2f->second;
6740 // if there are several elements at the same distance, select one
6741 // with GC closest to the point
6742 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
6743 double minDistToGC = 0;
6744 for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
6746 if ( minDistToGC == 0 )
6749 gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
6750 TXyzIterator(), gc ) / closestElem->NbNodes();
6751 minDistToGC = point.SquareDistance( gc );
6754 gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
6755 TXyzIterator(), gc ) / d2f->second->NbNodes();
6756 double d = point.SquareDistance( gc );
6757 if ( d < minDistToGC )
6760 closestElem = d2f->second;
6763 // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
6764 // <<closestElem->GetID() << " DIST " << minDist << endl;
6769 // NOT IMPLEMENTED SO FAR
6775 //================================================================================
6777 * \brief Classify the given point in the closed 2D mesh
6779 //================================================================================
6781 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6783 double tolerance = getTolerance();
6784 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6786 if ( _ebbTree ) delete _ebbTree;
6787 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6789 // Algo: analyse transition of a line starting at the point through mesh boundary;
6790 // try three lines parallel to axis of the coordinate system and perform rough
6791 // analysis. If solution is not clear perform thorough analysis.
6793 const int nbAxes = 3;
6794 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6795 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6796 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6797 multimap< int, int > nbInt2Axis; // to find the simplest case
6798 for ( int axis = 0; axis < nbAxes; ++axis )
6800 gp_Ax1 lineAxis( point, axisDir[axis]);
6801 gp_Lin line ( lineAxis );
6803 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6804 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6806 // Intersect faces with the line
6808 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6809 TIDSortedElemSet::iterator face = suspectFaces.begin();
6810 for ( ; face != suspectFaces.end(); ++face )
6814 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6815 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6817 // perform intersection
6818 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6819 if ( !intersection.IsDone() )
6821 if ( intersection.IsInQuadric() )
6823 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6825 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6827 gp_Pnt intersectionPoint = intersection.Point(1);
6828 if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance ))
6829 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6832 // Analyse intersections roughly
6834 int nbInter = u2inters.size();
6838 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6839 if ( nbInter == 1 ) // not closed mesh
6840 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6842 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6845 if ( (f<0) == (l<0) )
6848 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6849 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6850 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6853 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6855 if ( _outerFacesFound ) break; // pass to thorough analysis
6857 } // three attempts - loop on CS axes
6859 // Analyse intersections thoroughly.
6860 // We make two loops maximum, on the first one we only exclude touching intersections,
6861 // on the second, if situation is still unclear, we gather and use information on
6862 // position of faces (internal or outer). If faces position is already gathered,
6863 // we make the second loop right away.
6865 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6867 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6868 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6870 int axis = nb_axis->second;
6871 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6873 gp_Ax1 lineAxis( point, axisDir[axis]);
6874 gp_Lin line ( lineAxis );
6876 // add tangent intersections to u2inters
6878 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6879 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6880 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6881 u2inters.insert(make_pair( param, *tgtInt ));
6882 tangentInters[ axis ].clear();
6884 // Count intersections before and after the point excluding touching ones.
6885 // If hasPositionInfo we count intersections of outer boundary only
6887 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6888 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6889 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6890 bool ok = ! u_int1->second._coincides;
6891 while ( ok && u_int1 != u2inters.end() )
6893 double u = u_int1->first;
6894 bool touchingInt = false;
6895 if ( ++u_int2 != u2inters.end() )
6897 // skip intersections at the same point (if the line passes through edge or node)
6899 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6905 // skip tangent intersections
6907 const SMDS_MeshElement* prevFace = u_int1->second._face;
6908 while ( ok && u_int2->second._coincides )
6910 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6916 ok = ( u_int2 != u2inters.end() );
6921 // skip intersections at the same point after tangent intersections
6924 double u2 = u_int2->first;
6926 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6932 // decide if we skipped a touching intersection
6933 if ( nbSamePnt + nbTgt > 0 )
6935 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6936 map< double, TInters >::iterator u_int = u_int1;
6937 for ( ; u_int != u_int2; ++u_int )
6939 if ( u_int->second._coincides ) continue;
6940 double dot = u_int->second._faceNorm * line.Direction();
6941 if ( dot > maxDot ) maxDot = dot;
6942 if ( dot < minDot ) minDot = dot;
6944 touchingInt = ( minDot*maxDot < 0 );
6949 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6960 u_int1 = u_int2; // to next intersection
6962 } // loop on intersections with one line
6966 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6969 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6972 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6973 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6975 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6978 if ( (f<0) == (l<0) )
6981 if ( hasPositionInfo )
6982 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6984 } // loop on intersections of the tree lines - thorough analysis
6986 if ( !hasPositionInfo )
6988 // gather info on faces position - is face in the outer boundary or not
6989 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6990 findOuterBoundary( u2inters.begin()->second._face );
6993 } // two attempts - with and w/o faces position info in the mesh
6995 return TopAbs_UNKNOWN;
6998 //=======================================================================
7000 * \brief Return elements possibly intersecting the line
7002 //=======================================================================
7004 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7005 SMDSAbs_ElementType type,
7006 vector< const SMDS_MeshElement* >& foundElems)
7008 if ( !_ebbTree || _elementType != type )
7010 if ( _ebbTree ) delete _ebbTree;
7011 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7013 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7014 _ebbTree->getElementsNearLine( line, suspectFaces );
7015 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7018 //=======================================================================
7020 * \brief Return SMESH_ElementSearcher
7022 //=======================================================================
7024 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7026 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7029 //=======================================================================
7031 * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7033 //=======================================================================
7035 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7037 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7040 //=======================================================================
7042 * \brief Return true if the point is IN or ON of the element
7044 //=======================================================================
7046 bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7048 if ( element->GetType() == SMDSAbs_Volume)
7050 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7053 // get ordered nodes
7055 vector< gp_XYZ > xyz;
7056 vector<const SMDS_MeshNode*> nodeList;
7058 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7059 if ( element->IsQuadratic() ) {
7060 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7061 nodeIt = f->interlacedNodesElemIterator();
7062 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7063 nodeIt = e->interlacedNodesElemIterator();
7065 while ( nodeIt->more() )
7067 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7068 xyz.push_back( SMESH_TNodeXYZ(node) );
7069 nodeList.push_back(node);
7072 int i, nbNodes = element->NbNodes();
7074 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7076 // compute face normal
7077 gp_Vec faceNorm(0,0,0);
7078 xyz.push_back( xyz.front() );
7079 nodeList.push_back( nodeList.front() );
7080 for ( i = 0; i < nbNodes; ++i )
7082 gp_Vec edge1( xyz[i+1], xyz[i]);
7083 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7084 faceNorm += edge1 ^ edge2;
7086 double normSize = faceNorm.Magnitude();
7087 if ( normSize <= tol )
7089 // degenerated face: point is out if it is out of all face edges
7090 for ( i = 0; i < nbNodes; ++i )
7092 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7093 if ( !IsOut( &edge, point, tol ))
7098 faceNorm /= normSize;
7100 // check if the point lays on face plane
7101 gp_Vec n2p( xyz[0], point );
7102 if ( fabs( n2p * faceNorm ) > tol )
7103 return true; // not on face plane
7105 // check if point is out of face boundary:
7106 // define it by closest transition of a ray point->infinity through face boundary
7107 // on the face plane.
7108 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7109 // to find intersections of the ray with the boundary.
7111 gp_Vec plnNorm = ray ^ faceNorm;
7112 normSize = plnNorm.Magnitude();
7113 if ( normSize <= tol ) return false; // point coincides with the first node
7114 plnNorm /= normSize;
7115 // for each node of the face, compute its signed distance to the plane
7116 vector<double> dist( nbNodes + 1);
7117 for ( i = 0; i < nbNodes; ++i )
7119 gp_Vec n2p( xyz[i], point );
7120 dist[i] = n2p * plnNorm;
7122 dist.back() = dist.front();
7123 // find the closest intersection
7125 double rClosest, distClosest = 1e100;;
7127 for ( i = 0; i < nbNodes; ++i )
7130 if ( fabs( dist[i]) < tol )
7132 else if ( fabs( dist[i+1]) < tol )
7134 else if ( dist[i] * dist[i+1] < 0 )
7135 r = dist[i] / ( dist[i] - dist[i+1] );
7137 continue; // no intersection
7138 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7139 gp_Vec p2int ( point, pInt);
7140 if ( p2int * ray > -tol ) // right half-space
7142 double intDist = p2int.SquareMagnitude();
7143 if ( intDist < distClosest )
7148 distClosest = intDist;
7153 return true; // no intesections - out
7155 // analyse transition
7156 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7157 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7158 gp_Vec p2int ( point, pClosest );
7159 bool out = (edgeNorm * p2int) < -tol;
7160 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7163 // ray pass through a face node; analyze transition through an adjacent edge
7164 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7165 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7166 gp_Vec edgeAdjacent( p1, p2 );
7167 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7168 bool out2 = (edgeNorm2 * p2int) < -tol;
7170 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7171 return covexCorner ? (out || out2) : (out && out2);
7173 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7175 // point is out of edge if it is NOT ON any straight part of edge
7176 // (we consider quadratic edge as being composed of two straight parts)
7177 for ( i = 1; i < nbNodes; ++i )
7179 gp_Vec edge( xyz[i-1], xyz[i]);
7180 gp_Vec n1p ( xyz[i-1], point);
7181 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7184 gp_Vec n2p( xyz[i], point );
7185 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7187 return false; // point is ON this part
7191 // Node or 0D element -------------------------------------------------------------------------
7193 gp_Vec n2p ( xyz[0], point );
7194 return n2p.Magnitude() <= tol;
7199 //=======================================================================
7203 // Position of a point relative to a segment
7207 // VERTEX 1 o----ON-----> VERTEX 2
7211 enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
7212 POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
7216 int _index; // index of vertex or segment
7218 PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
7219 bool operator < (const PointPos& other ) const
7221 if ( _name == other._name )
7222 return ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
7223 return _name < other._name;
7227 //================================================================================
7229 * \brief Return of a point relative to a segment
7230 * \param point2D - the point to analyze position of
7231 * \param xyVec - end points of segments
7232 * \param index0 - 0-based index of the first point of segment
7233 * \param posToFindOut - flags of positions to detect
7234 * \retval PointPos - point position
7236 //================================================================================
7238 PointPos getPointPosition( const gp_XY& point2D,
7239 const gp_XY* segEnds,
7240 const int index0 = 0,
7241 const int posToFindOut = POS_ALL)
7243 const gp_XY& p1 = segEnds[ index0 ];
7244 const gp_XY& p2 = segEnds[ index0+1 ];
7245 const gp_XY grad = p2 - p1;
7247 if ( posToFindOut & POS_VERTEX )
7249 // check if the point2D is at "vertex 1" zone
7250 gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
7251 p1.Y() + grad.X() ) };
7252 if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
7253 return PointPos( POS_VERTEX, index0 );
7255 // check if the point2D is at "vertex 2" zone
7256 gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
7257 p2.Y() + grad.X() ) };
7258 if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
7259 return PointPos( POS_VERTEX, index0 + 1);
7261 double edgeEquation =
7262 ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
7263 return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
7267 //=======================================================================
7269 * \brief Return minimal distance from a point to a face
7271 * Currently we ignore non-planarity and 2nd order of face
7273 //=======================================================================
7275 double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face,
7276 const gp_Pnt& point )
7278 double badDistance = -1;
7279 if ( !face ) return badDistance;
7281 // coordinates of nodes (medium nodes, if any, ignored)
7282 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
7283 vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
7284 xyz.resize( face->NbCornerNodes()+1 );
7286 // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
7287 // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
7289 gp_Vec OZ ( xyz[0], xyz[1] );
7290 gp_Vec OX ( xyz[0], xyz[2] );
7291 if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
7293 if ( xyz.size() < 4 ) return badDistance;
7294 OZ = gp_Vec ( xyz[0], xyz[2] );
7295 OX = gp_Vec ( xyz[0], xyz[3] );
7299 tgtCS = gp_Ax3( xyz[0], OZ, OX );
7301 catch ( Standard_Failure ) {
7304 trsf.SetTransformation( tgtCS );
7306 // move all the nodes to 2D
7307 vector<gp_XY> xy( xyz.size() );
7308 for ( size_t i = 0;i < xyz.size()-1; ++i )
7310 gp_XYZ p3d = xyz[i];
7311 trsf.Transforms( p3d );
7312 xy[i].SetCoord( p3d.X(), p3d.Z() );
7314 xyz.back() = xyz.front();
7315 xy.back() = xy.front();
7317 // // move the point in 2D
7318 gp_XYZ tmpPnt = point.XYZ();
7319 trsf.Transforms( tmpPnt );
7320 gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
7322 // loop on segments of the face to analyze point position ralative to the face
7323 set< PointPos > pntPosSet;
7324 for ( size_t i = 1; i < xy.size(); ++i )
7326 PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
7327 pntPosSet.insert( pos );
7331 PointPos pos = *pntPosSet.begin();
7332 // cout << "Face " << face->GetID() << " DIST: ";
7333 switch ( pos._name )
7336 // point is most close to a segment
7337 gp_Vec p0p1( point, xyz[ pos._index ] );
7338 gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
7340 double projDist = p0p1 * p1p2; // distance projected to the segment
7341 gp_Vec projVec = p1p2 * projDist;
7342 gp_Vec distVec = p0p1 - projVec;
7343 // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID()
7344 // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
7345 return distVec.Magnitude();
7348 // point is inside the face
7349 double distToFacePlane = tmpPnt.Y();
7350 // cout << distToFacePlane << ", INSIDE " << endl;
7351 return Abs( distToFacePlane );
7354 // point is most close to a node
7355 gp_Vec distVec( point, xyz[ pos._index ]);
7356 // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
7357 return distVec.Magnitude();
7363 //=======================================================================
7364 //function : SimplifyFace
7366 //=======================================================================
7367 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7368 vector<const SMDS_MeshNode *>& poly_nodes,
7369 vector<int>& quantities) const
7371 int nbNodes = faceNodes.size();
7376 set<const SMDS_MeshNode*> nodeSet;
7378 // get simple seq of nodes
7379 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7380 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7381 int iSimple = 0, nbUnique = 0;
7383 simpleNodes[iSimple++] = faceNodes[0];
7385 for (int iCur = 1; iCur < nbNodes; iCur++) {
7386 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7387 simpleNodes[iSimple++] = faceNodes[iCur];
7388 if (nodeSet.insert( faceNodes[iCur] ).second)
7392 int nbSimple = iSimple;
7393 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7403 bool foundLoop = (nbSimple > nbUnique);
7406 set<const SMDS_MeshNode*> loopSet;
7407 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7408 const SMDS_MeshNode* n = simpleNodes[iSimple];
7409 if (!loopSet.insert( n ).second) {
7413 int iC = 0, curLast = iSimple;
7414 for (; iC < curLast; iC++) {
7415 if (simpleNodes[iC] == n) break;
7417 int loopLen = curLast - iC;
7419 // create sub-element
7421 quantities.push_back(loopLen);
7422 for (; iC < curLast; iC++) {
7423 poly_nodes.push_back(simpleNodes[iC]);
7426 // shift the rest nodes (place from the first loop position)
7427 for (iC = curLast + 1; iC < nbSimple; iC++) {
7428 simpleNodes[iC - loopLen] = simpleNodes[iC];
7430 nbSimple -= loopLen;
7433 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7434 } // while (foundLoop)
7438 quantities.push_back(iSimple);
7439 for (int i = 0; i < iSimple; i++)
7440 poly_nodes.push_back(simpleNodes[i]);
7446 //=======================================================================
7447 //function : MergeNodes
7448 //purpose : In each group, the cdr of nodes are substituted by the first one
7450 //=======================================================================
7452 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7454 MESSAGE("MergeNodes");
7455 myLastCreatedElems.Clear();
7456 myLastCreatedNodes.Clear();
7458 SMESHDS_Mesh* aMesh = GetMeshDS();
7460 TNodeNodeMap nodeNodeMap; // node to replace - new node
7461 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7462 list< int > rmElemIds, rmNodeIds;
7464 // Fill nodeNodeMap and elems
7466 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7467 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7468 list<const SMDS_MeshNode*>& nodes = *grIt;
7469 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7470 const SMDS_MeshNode* nToKeep = *nIt;
7471 //MESSAGE("node to keep " << nToKeep->GetID());
7472 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7473 const SMDS_MeshNode* nToRemove = *nIt;
7474 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7475 if ( nToRemove != nToKeep ) {
7476 //MESSAGE(" node to remove " << nToRemove->GetID());
7477 rmNodeIds.push_back( nToRemove->GetID() );
7478 AddToSameGroups( nToKeep, nToRemove, aMesh );
7481 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7482 while ( invElemIt->more() ) {
7483 const SMDS_MeshElement* elem = invElemIt->next();
7488 // Change element nodes or remove an element
7490 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7491 for ( ; eIt != elems.end(); eIt++ ) {
7492 const SMDS_MeshElement* elem = *eIt;
7493 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7494 int nbNodes = elem->NbNodes();
7495 int aShapeId = FindShape( elem );
7497 set<const SMDS_MeshNode*> nodeSet;
7498 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7499 int iUnique = 0, iCur = 0, nbRepl = 0;
7500 vector<int> iRepl( nbNodes );
7502 // get new seq of nodes
7503 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7504 while ( itN->more() ) {
7505 const SMDS_MeshNode* n =
7506 static_cast<const SMDS_MeshNode*>( itN->next() );
7508 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7509 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7511 // BUG 0020185: begin
7513 bool stopRecur = false;
7514 set<const SMDS_MeshNode*> nodesRecur;
7515 nodesRecur.insert(n);
7516 while (!stopRecur) {
7517 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7518 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7519 n = (*nnIt_i).second;
7520 if (!nodesRecur.insert(n).second) {
7521 // error: recursive dependancy
7531 curNodes[ iCur ] = n;
7532 bool isUnique = nodeSet.insert( n ).second;
7534 uniqueNodes[ iUnique++ ] = n;
7536 iRepl[ nbRepl++ ] = iCur;
7540 // Analyse element topology after replacement
7543 int nbUniqueNodes = nodeSet.size();
7544 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7545 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7546 // Polygons and Polyhedral volumes
7547 if (elem->IsPoly()) {
7549 if (elem->GetType() == SMDSAbs_Face) {
7551 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7553 for (; inode < nbNodes; inode++) {
7554 face_nodes[inode] = curNodes[inode];
7557 vector<const SMDS_MeshNode *> polygons_nodes;
7558 vector<int> quantities;
7559 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7562 for (int iface = 0; iface < nbNew; iface++) {
7563 int nbNodes = quantities[iface];
7564 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7565 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7566 poly_nodes[ii] = polygons_nodes[inode];
7568 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7569 myLastCreatedElems.Append(newElem);
7571 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7574 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7575 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7576 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7578 if (nbNew > 0) quid = nbNew - 1;
7579 vector<int> newquant(quantities.begin()+quid, quantities.end());
7580 const SMDS_MeshElement* newElem = 0;
7581 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7582 myLastCreatedElems.Append(newElem);
7583 if ( aShapeId && newElem )
7584 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7585 rmElemIds.push_back(elem->GetID());
7588 rmElemIds.push_back(elem->GetID());
7592 else if (elem->GetType() == SMDSAbs_Volume) {
7593 // Polyhedral volume
7594 if (nbUniqueNodes < 4) {
7595 rmElemIds.push_back(elem->GetID());
7598 // each face has to be analyzed in order to check volume validity
7599 const SMDS_VtkVolume* aPolyedre =
7600 dynamic_cast<const SMDS_VtkVolume*>( elem );
7602 int nbFaces = aPolyedre->NbFaces();
7604 vector<const SMDS_MeshNode *> poly_nodes;
7605 vector<int> quantities;
7607 for (int iface = 1; iface <= nbFaces; iface++) {
7608 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7609 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7611 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7612 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7613 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7614 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7615 faceNode = (*nnIt).second;
7617 faceNodes[inode - 1] = faceNode;
7620 SimplifyFace(faceNodes, poly_nodes, quantities);
7623 if (quantities.size() > 3) {
7624 // to be done: remove coincident faces
7627 if (quantities.size() > 3)
7629 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7630 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7631 const SMDS_MeshElement* newElem = 0;
7632 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7633 myLastCreatedElems.Append(newElem);
7634 if ( aShapeId && newElem )
7635 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7636 rmElemIds.push_back(elem->GetID());
7640 rmElemIds.push_back(elem->GetID());
7651 // TODO not all the possible cases are solved. Find something more generic?
7652 switch ( nbNodes ) {
7653 case 2: ///////////////////////////////////// EDGE
7654 isOk = false; break;
7655 case 3: ///////////////////////////////////// TRIANGLE
7656 isOk = false; break;
7658 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7660 else { //////////////////////////////////// QUADRANGLE
7661 if ( nbUniqueNodes < 3 )
7663 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7664 isOk = false; // opposite nodes stick
7665 //MESSAGE("isOk " << isOk);
7668 case 6: ///////////////////////////////////// PENTAHEDRON
7669 if ( nbUniqueNodes == 4 ) {
7670 // ---------------------------------> tetrahedron
7672 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7673 // all top nodes stick: reverse a bottom
7674 uniqueNodes[ 0 ] = curNodes [ 1 ];
7675 uniqueNodes[ 1 ] = curNodes [ 0 ];
7677 else if (nbRepl == 3 &&
7678 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7679 // all bottom nodes stick: set a top before
7680 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7681 uniqueNodes[ 0 ] = curNodes [ 3 ];
7682 uniqueNodes[ 1 ] = curNodes [ 4 ];
7683 uniqueNodes[ 2 ] = curNodes [ 5 ];
7685 else if (nbRepl == 4 &&
7686 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7687 // a lateral face turns into a line: reverse a bottom
7688 uniqueNodes[ 0 ] = curNodes [ 1 ];
7689 uniqueNodes[ 1 ] = curNodes [ 0 ];
7694 else if ( nbUniqueNodes == 5 ) {
7695 // PENTAHEDRON --------------------> 2 tetrahedrons
7696 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7697 // a bottom node sticks with a linked top one
7699 SMDS_MeshElement* newElem =
7700 aMesh->AddVolume(curNodes[ 3 ],
7703 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7704 myLastCreatedElems.Append(newElem);
7706 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7707 // 2. : reverse a bottom
7708 uniqueNodes[ 0 ] = curNodes [ 1 ];
7709 uniqueNodes[ 1 ] = curNodes [ 0 ];
7719 if(elem->IsQuadratic()) { // Quadratic quadrangle
7731 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7734 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7736 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7737 uniqueNodes[0] = curNodes[0];
7738 uniqueNodes[1] = curNodes[2];
7739 uniqueNodes[2] = curNodes[3];
7740 uniqueNodes[3] = curNodes[5];
7741 uniqueNodes[4] = curNodes[6];
7742 uniqueNodes[5] = curNodes[7];
7745 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7746 uniqueNodes[0] = curNodes[0];
7747 uniqueNodes[1] = curNodes[1];
7748 uniqueNodes[2] = curNodes[2];
7749 uniqueNodes[3] = curNodes[4];
7750 uniqueNodes[4] = curNodes[5];
7751 uniqueNodes[5] = curNodes[6];
7754 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7755 uniqueNodes[0] = curNodes[1];
7756 uniqueNodes[1] = curNodes[2];
7757 uniqueNodes[2] = curNodes[3];
7758 uniqueNodes[3] = curNodes[5];
7759 uniqueNodes[4] = curNodes[6];
7760 uniqueNodes[5] = curNodes[0];
7763 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7764 uniqueNodes[0] = curNodes[0];
7765 uniqueNodes[1] = curNodes[1];
7766 uniqueNodes[2] = curNodes[3];
7767 uniqueNodes[3] = curNodes[4];
7768 uniqueNodes[4] = curNodes[6];
7769 uniqueNodes[5] = curNodes[7];
7772 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7773 uniqueNodes[0] = curNodes[0];
7774 uniqueNodes[1] = curNodes[2];
7775 uniqueNodes[2] = curNodes[3];
7776 uniqueNodes[3] = curNodes[1];
7777 uniqueNodes[4] = curNodes[6];
7778 uniqueNodes[5] = curNodes[7];
7781 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7782 uniqueNodes[0] = curNodes[0];
7783 uniqueNodes[1] = curNodes[1];
7784 uniqueNodes[2] = curNodes[2];
7785 uniqueNodes[3] = curNodes[4];
7786 uniqueNodes[4] = curNodes[5];
7787 uniqueNodes[5] = curNodes[7];
7790 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7791 uniqueNodes[0] = curNodes[0];
7792 uniqueNodes[1] = curNodes[1];
7793 uniqueNodes[2] = curNodes[3];
7794 uniqueNodes[3] = curNodes[4];
7795 uniqueNodes[4] = curNodes[2];
7796 uniqueNodes[5] = curNodes[7];
7799 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7800 uniqueNodes[0] = curNodes[0];
7801 uniqueNodes[1] = curNodes[1];
7802 uniqueNodes[2] = curNodes[2];
7803 uniqueNodes[3] = curNodes[4];
7804 uniqueNodes[4] = curNodes[5];
7805 uniqueNodes[5] = curNodes[3];
7810 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7813 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7817 //////////////////////////////////// HEXAHEDRON
7819 SMDS_VolumeTool hexa (elem);
7820 hexa.SetExternalNormal();
7821 if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7822 //////////////////////// HEX ---> 1 tetrahedron
7823 for ( int iFace = 0; iFace < 6; iFace++ ) {
7824 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7825 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7826 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7827 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7828 // one face turns into a point ...
7829 int iOppFace = hexa.GetOppFaceIndex( iFace );
7830 ind = hexa.GetFaceNodesIndices( iOppFace );
7832 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7833 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7836 if ( nbStick == 1 ) {
7837 // ... and the opposite one - into a triangle.
7839 ind = hexa.GetFaceNodesIndices( iFace );
7840 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7847 else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7848 //////////////////////// HEX ---> 1 prism
7849 int nbTria = 0, iTria[3];
7850 const int *ind; // indices of face nodes
7851 // look for triangular faces
7852 for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7853 ind = hexa.GetFaceNodesIndices( iFace );
7854 TIDSortedNodeSet faceNodes;
7855 for ( iCur = 0; iCur < 4; iCur++ )
7856 faceNodes.insert( curNodes[ind[iCur]] );
7857 if ( faceNodes.size() == 3 )
7858 iTria[ nbTria++ ] = iFace;
7860 // check if triangles are opposite
7861 if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7864 // set nodes of the bottom triangle
7865 ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7867 for ( iCur = 0; iCur < 4; iCur++ )
7868 if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7869 indB.push_back( ind[iCur] );
7870 if ( !hexa.IsForward() )
7871 std::swap( indB[0], indB[2] );
7872 for ( iCur = 0; iCur < 3; iCur++ )
7873 uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7874 // set nodes of the top triangle
7875 const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7876 for ( iCur = 0; iCur < 3; ++iCur )
7877 for ( int j = 0; j < 4; ++j )
7878 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7880 uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7886 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7887 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7888 for ( int iFace = 0; iFace < 6; iFace++ ) {
7889 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7890 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7891 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7892 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7893 // one face turns into a point ...
7894 int iOppFace = hexa.GetOppFaceIndex( iFace );
7895 ind = hexa.GetFaceNodesIndices( iOppFace );
7897 iUnique = 2; // reverse a tetrahedron 1 bottom
7898 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7899 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7901 else if ( iUnique >= 0 )
7902 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7904 if ( nbStick == 0 ) {
7905 // ... and the opposite one is a quadrangle
7907 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7908 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7911 SMDS_MeshElement* newElem =
7912 aMesh->AddVolume(curNodes[ind[ 0 ]],
7915 curNodes[indTop[ 0 ]]);
7916 myLastCreatedElems.Append(newElem);
7918 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7925 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7926 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7927 // find indices of quad and tri faces
7928 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7929 for ( iFace = 0; iFace < 6; iFace++ ) {
7930 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7932 for ( iCur = 0; iCur < 4; iCur++ )
7933 nodeSet.insert( curNodes[ind[ iCur ]] );
7934 nbUniqueNodes = nodeSet.size();
7935 if ( nbUniqueNodes == 3 )
7936 iTriFace[ nbTri++ ] = iFace;
7937 else if ( nbUniqueNodes == 4 )
7938 iQuadFace[ nbQuad++ ] = iFace;
7940 if (nbQuad == 2 && nbTri == 4 &&
7941 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7942 // 2 opposite quadrangles stuck with a diagonal;
7943 // sample groups of merged indices: (0-4)(2-6)
7944 // --------------------------------------------> 2 tetrahedrons
7945 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7946 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7947 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7948 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7949 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7950 // stuck with 0-2 diagonal
7958 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7959 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7960 // stuck with 1-3 diagonal
7972 uniqueNodes[ 0 ] = curNodes [ i0 ];
7973 uniqueNodes[ 1 ] = curNodes [ i1d ];
7974 uniqueNodes[ 2 ] = curNodes [ i3d ];
7975 uniqueNodes[ 3 ] = curNodes [ i0t ];
7978 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7982 myLastCreatedElems.Append(newElem);
7984 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7987 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7988 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7989 // --------------------------------------------> prism
7990 // find 2 opposite triangles
7992 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7993 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7994 // find indices of kept and replaced nodes
7995 // and fill unique nodes of 2 opposite triangles
7996 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7997 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7998 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7999 // fill unique nodes
8002 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
8003 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
8004 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
8006 // iCur of a linked node of the opposite face (make normals co-directed):
8007 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
8008 // check that correspondent corners of triangles are linked
8009 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
8012 uniqueNodes[ iUnique ] = n;
8013 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
8022 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
8025 MESSAGE("MergeNodes() removes hexahedron "<< elem);
8032 } // switch ( nbNodes )
8034 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
8036 if ( isOk ) { // the elem remains valid after sticking nodes
8037 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
8039 // Change nodes of polyedre
8040 const SMDS_VtkVolume* aPolyedre =
8041 dynamic_cast<const SMDS_VtkVolume*>( elem );
8043 int nbFaces = aPolyedre->NbFaces();
8045 vector<const SMDS_MeshNode *> poly_nodes;
8046 vector<int> quantities (nbFaces);
8048 for (int iface = 1; iface <= nbFaces; iface++) {
8049 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
8050 quantities[iface - 1] = nbFaceNodes;
8052 for (inode = 1; inode <= nbFaceNodes; inode++) {
8053 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
8055 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
8056 if (nnIt != nodeNodeMap.end()) { // curNode sticks
8057 curNode = (*nnIt).second;
8059 poly_nodes.push_back(curNode);
8062 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
8065 else // replace non-polyhedron elements
8067 const SMDSAbs_ElementType etyp = elem->GetType();
8068 const int elemId = elem->GetID();
8069 const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
8070 uniqueNodes.resize(nbUniqueNodes);
8072 SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
8074 aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
8075 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
8076 if ( sm && newElem )
8077 sm->AddElement( newElem );
8078 if ( elem != newElem )
8079 ReplaceElemInGroups( elem, newElem, aMesh );
8083 // Remove invalid regular element or invalid polygon
8084 rmElemIds.push_back( elem->GetID() );
8087 } // loop on elements
8089 // Remove bad elements, then equal nodes (order important)
8091 Remove( rmElemIds, false );
8092 Remove( rmNodeIds, true );
8097 // ========================================================
8098 // class : SortableElement
8099 // purpose : allow sorting elements basing on their nodes
8100 // ========================================================
8101 class SortableElement : public set <const SMDS_MeshElement*>
8105 SortableElement( const SMDS_MeshElement* theElem )
8108 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
8109 while ( nodeIt->more() )
8110 this->insert( nodeIt->next() );
8113 const SMDS_MeshElement* Get() const
8116 void Set(const SMDS_MeshElement* e) const
8121 mutable const SMDS_MeshElement* myElem;
8124 //=======================================================================
8125 //function : FindEqualElements
8126 //purpose : Return list of group of elements built on the same nodes.
8127 // Search among theElements or in the whole mesh if theElements is empty
8128 //=======================================================================
8129 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
8130 TListOfListOfElementsID & theGroupsOfElementsID)
8132 myLastCreatedElems.Clear();
8133 myLastCreatedNodes.Clear();
8135 typedef set<const SMDS_MeshElement*> TElemsSet;
8136 typedef map< SortableElement, int > TMapOfNodeSet;
8137 typedef list<int> TGroupOfElems;
8140 if ( theElements.empty() )
8141 { // get all elements in the mesh
8142 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8143 while ( eIt->more() )
8144 elems.insert( elems.end(), eIt->next());
8147 elems = theElements;
8149 vector< TGroupOfElems > arrayOfGroups;
8150 TGroupOfElems groupOfElems;
8151 TMapOfNodeSet mapOfNodeSet;
8153 TElemsSet::iterator elemIt = elems.begin();
8154 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8155 const SMDS_MeshElement* curElem = *elemIt;
8156 SortableElement SE(curElem);
8159 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8160 if( !(pp.second) ) {
8161 TMapOfNodeSet::iterator& itSE = pp.first;
8162 ind = (*itSE).second;
8163 arrayOfGroups[ind].push_back(curElem->GetID());
8166 groupOfElems.clear();
8167 groupOfElems.push_back(curElem->GetID());
8168 arrayOfGroups.push_back(groupOfElems);
8173 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8174 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8175 groupOfElems = *groupIt;
8176 if ( groupOfElems.size() > 1 ) {
8177 groupOfElems.sort();
8178 theGroupsOfElementsID.push_back(groupOfElems);
8183 //=======================================================================
8184 //function : MergeElements
8185 //purpose : In each given group, substitute all elements by the first one.
8186 //=======================================================================
8188 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8190 myLastCreatedElems.Clear();
8191 myLastCreatedNodes.Clear();
8193 typedef list<int> TListOfIDs;
8194 TListOfIDs rmElemIds; // IDs of elems to remove
8196 SMESHDS_Mesh* aMesh = GetMeshDS();
8198 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8199 while ( groupsIt != theGroupsOfElementsID.end() ) {
8200 TListOfIDs& aGroupOfElemID = *groupsIt;
8201 aGroupOfElemID.sort();
8202 int elemIDToKeep = aGroupOfElemID.front();
8203 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8204 aGroupOfElemID.pop_front();
8205 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8206 while ( idIt != aGroupOfElemID.end() ) {
8207 int elemIDToRemove = *idIt;
8208 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8209 // add the kept element in groups of removed one (PAL15188)
8210 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8211 rmElemIds.push_back( elemIDToRemove );
8217 Remove( rmElemIds, false );
8220 //=======================================================================
8221 //function : MergeEqualElements
8222 //purpose : Remove all but one of elements built on the same nodes.
8223 //=======================================================================
8225 void SMESH_MeshEditor::MergeEqualElements()
8227 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8228 to merge equal elements in the whole mesh */
8229 TListOfListOfElementsID aGroupsOfElementsID;
8230 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8231 MergeElements(aGroupsOfElementsID);
8234 //=======================================================================
8235 //function : FindFaceInSet
8236 //purpose : Return a face having linked nodes n1 and n2 and which is
8237 // - not in avoidSet,
8238 // - in elemSet provided that !elemSet.empty()
8239 // i1 and i2 optionally returns indices of n1 and n2
8240 //=======================================================================
8242 const SMDS_MeshElement*
8243 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8244 const SMDS_MeshNode* n2,
8245 const TIDSortedElemSet& elemSet,
8246 const TIDSortedElemSet& avoidSet,
8252 const SMDS_MeshElement* face = 0;
8254 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8255 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8256 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8258 //MESSAGE("in while ( invElemIt->more() && !face )");
8259 const SMDS_MeshElement* elem = invElemIt->next();
8260 if (avoidSet.count( elem ))
8262 if ( !elemSet.empty() && !elemSet.count( elem ))
8265 i1 = elem->GetNodeIndex( n1 );
8266 // find a n2 linked to n1
8267 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8268 for ( int di = -1; di < 2 && !face; di += 2 )
8270 i2 = (i1+di+nbN) % nbN;
8271 if ( elem->GetNode( i2 ) == n2 )
8274 if ( !face && elem->IsQuadratic())
8276 // analysis for quadratic elements using all nodes
8277 const SMDS_VtkFace* F =
8278 dynamic_cast<const SMDS_VtkFace*>(elem);
8279 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8280 // use special nodes iterator
8281 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8282 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8283 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8285 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8286 if ( n1 == prevN && n2 == n )
8290 else if ( n2 == prevN && n1 == n )
8292 face = elem; swap( i1, i2 );
8298 if ( n1ind ) *n1ind = i1;
8299 if ( n2ind ) *n2ind = i2;
8303 //=======================================================================
8304 //function : findAdjacentFace
8306 //=======================================================================
8308 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8309 const SMDS_MeshNode* n2,
8310 const SMDS_MeshElement* elem)
8312 TIDSortedElemSet elemSet, avoidSet;
8314 avoidSet.insert ( elem );
8315 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8318 //=======================================================================
8319 //function : FindFreeBorder
8321 //=======================================================================
8323 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8325 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8326 const SMDS_MeshNode* theSecondNode,
8327 const SMDS_MeshNode* theLastNode,
8328 list< const SMDS_MeshNode* > & theNodes,
8329 list< const SMDS_MeshElement* >& theFaces)
8331 if ( !theFirstNode || !theSecondNode )
8333 // find border face between theFirstNode and theSecondNode
8334 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8338 theFaces.push_back( curElem );
8339 theNodes.push_back( theFirstNode );
8340 theNodes.push_back( theSecondNode );
8342 //vector<const SMDS_MeshNode*> nodes;
8343 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8344 TIDSortedElemSet foundElems;
8345 bool needTheLast = ( theLastNode != 0 );
8347 while ( nStart != theLastNode ) {
8348 if ( nStart == theFirstNode )
8349 return !needTheLast;
8351 // find all free border faces sharing form nStart
8353 list< const SMDS_MeshElement* > curElemList;
8354 list< const SMDS_MeshNode* > nStartList;
8355 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8356 while ( invElemIt->more() ) {
8357 const SMDS_MeshElement* e = invElemIt->next();
8358 if ( e == curElem || foundElems.insert( e ).second ) {
8360 int iNode = 0, nbNodes = e->NbNodes();
8361 //const SMDS_MeshNode* nodes[nbNodes+1];
8362 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8364 if(e->IsQuadratic()) {
8365 const SMDS_VtkFace* F =
8366 dynamic_cast<const SMDS_VtkFace*>(e);
8367 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8368 // use special nodes iterator
8369 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8370 while( anIter->more() ) {
8371 nodes[ iNode++ ] = cast2Node(anIter->next());
8375 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8376 while ( nIt->more() )
8377 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8379 nodes[ iNode ] = nodes[ 0 ];
8381 for ( iNode = 0; iNode < nbNodes; iNode++ )
8382 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8383 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8384 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8386 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8387 curElemList.push_back( e );
8391 // analyse the found
8393 int nbNewBorders = curElemList.size();
8394 if ( nbNewBorders == 0 ) {
8395 // no free border furthermore
8396 return !needTheLast;
8398 else if ( nbNewBorders == 1 ) {
8399 // one more element found
8401 nStart = nStartList.front();
8402 curElem = curElemList.front();
8403 theFaces.push_back( curElem );
8404 theNodes.push_back( nStart );
8407 // several continuations found
8408 list< const SMDS_MeshElement* >::iterator curElemIt;
8409 list< const SMDS_MeshNode* >::iterator nStartIt;
8410 // check if one of them reached the last node
8411 if ( needTheLast ) {
8412 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8413 curElemIt!= curElemList.end();
8414 curElemIt++, nStartIt++ )
8415 if ( *nStartIt == theLastNode ) {
8416 theFaces.push_back( *curElemIt );
8417 theNodes.push_back( *nStartIt );
8421 // find the best free border by the continuations
8422 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8423 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8424 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8425 curElemIt!= curElemList.end();
8426 curElemIt++, nStartIt++ )
8428 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8429 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8430 // find one more free border
8431 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8435 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8436 // choice: clear a worse one
8437 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8438 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8439 contNodes[ iWorse ].clear();
8440 contFaces[ iWorse ].clear();
8443 if ( contNodes[0].empty() && contNodes[1].empty() )
8446 // append the best free border
8447 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8448 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8449 theNodes.pop_back(); // remove nIgnore
8450 theNodes.pop_back(); // remove nStart
8451 theFaces.pop_back(); // remove curElem
8452 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8453 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8454 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8455 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8458 } // several continuations found
8459 } // while ( nStart != theLastNode )
8464 //=======================================================================
8465 //function : CheckFreeBorderNodes
8466 //purpose : Return true if the tree nodes are on a free border
8467 //=======================================================================
8469 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8470 const SMDS_MeshNode* theNode2,
8471 const SMDS_MeshNode* theNode3)
8473 list< const SMDS_MeshNode* > nodes;
8474 list< const SMDS_MeshElement* > faces;
8475 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8478 //=======================================================================
8479 //function : SewFreeBorder
8481 //=======================================================================
8483 SMESH_MeshEditor::Sew_Error
8484 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8485 const SMDS_MeshNode* theBordSecondNode,
8486 const SMDS_MeshNode* theBordLastNode,
8487 const SMDS_MeshNode* theSideFirstNode,
8488 const SMDS_MeshNode* theSideSecondNode,
8489 const SMDS_MeshNode* theSideThirdNode,
8490 const bool theSideIsFreeBorder,
8491 const bool toCreatePolygons,
8492 const bool toCreatePolyedrs)
8494 myLastCreatedElems.Clear();
8495 myLastCreatedNodes.Clear();
8497 MESSAGE("::SewFreeBorder()");
8498 Sew_Error aResult = SEW_OK;
8500 // ====================================
8501 // find side nodes and elements
8502 // ====================================
8504 list< const SMDS_MeshNode* > nSide[ 2 ];
8505 list< const SMDS_MeshElement* > eSide[ 2 ];
8506 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8507 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8511 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8512 nSide[0], eSide[0])) {
8513 MESSAGE(" Free Border 1 not found " );
8514 aResult = SEW_BORDER1_NOT_FOUND;
8516 if (theSideIsFreeBorder) {
8519 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8520 nSide[1], eSide[1])) {
8521 MESSAGE(" Free Border 2 not found " );
8522 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8525 if ( aResult != SEW_OK )
8528 if (!theSideIsFreeBorder) {
8532 // -------------------------------------------------------------------------
8534 // 1. If nodes to merge are not coincident, move nodes of the free border
8535 // from the coord sys defined by the direction from the first to last
8536 // nodes of the border to the correspondent sys of the side 2
8537 // 2. On the side 2, find the links most co-directed with the correspondent
8538 // links of the free border
8539 // -------------------------------------------------------------------------
8541 // 1. Since sewing may break if there are volumes to split on the side 2,
8542 // we wont move nodes but just compute new coordinates for them
8543 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8544 TNodeXYZMap nBordXYZ;
8545 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8546 list< const SMDS_MeshNode* >::iterator nBordIt;
8548 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8549 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8550 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8551 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8552 double tol2 = 1.e-8;
8553 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8554 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8555 // Need node movement.
8557 // find X and Z axes to create trsf
8558 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8560 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8562 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8565 gp_Ax3 toBordAx( Pb1, Zb, X );
8566 gp_Ax3 fromSideAx( Ps1, Zs, X );
8567 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8569 gp_Trsf toBordSys, fromSide2Sys;
8570 toBordSys.SetTransformation( toBordAx );
8571 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8572 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8575 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8576 const SMDS_MeshNode* n = *nBordIt;
8577 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8578 toBordSys.Transforms( xyz );
8579 fromSide2Sys.Transforms( xyz );
8580 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8584 // just insert nodes XYZ in the nBordXYZ map
8585 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8586 const SMDS_MeshNode* n = *nBordIt;
8587 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8591 // 2. On the side 2, find the links most co-directed with the correspondent
8592 // links of the free border
8594 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8595 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8596 sideNodes.push_back( theSideFirstNode );
8598 bool hasVolumes = false;
8599 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8600 set<long> foundSideLinkIDs, checkedLinkIDs;
8601 SMDS_VolumeTool volume;
8602 //const SMDS_MeshNode* faceNodes[ 4 ];
8604 const SMDS_MeshNode* sideNode;
8605 const SMDS_MeshElement* sideElem;
8606 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8607 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8608 nBordIt = bordNodes.begin();
8610 // border node position and border link direction to compare with
8611 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8612 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8613 // choose next side node by link direction or by closeness to
8614 // the current border node:
8615 bool searchByDir = ( *nBordIt != theBordLastNode );
8617 // find the next node on the Side 2
8619 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8621 checkedLinkIDs.clear();
8622 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8624 // loop on inverse elements of current node (prevSideNode) on the Side 2
8625 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8626 while ( invElemIt->more() )
8628 const SMDS_MeshElement* elem = invElemIt->next();
8629 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8630 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8631 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8632 bool isVolume = volume.Set( elem );
8633 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8634 if ( isVolume ) // --volume
8636 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8637 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8638 if(elem->IsQuadratic()) {
8639 const SMDS_VtkFace* F =
8640 dynamic_cast<const SMDS_VtkFace*>(elem);
8641 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8642 // use special nodes iterator
8643 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8644 while( anIter->more() ) {
8645 nodes[ iNode ] = cast2Node(anIter->next());
8646 if ( nodes[ iNode++ ] == prevSideNode )
8647 iPrevNode = iNode - 1;
8651 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8652 while ( nIt->more() ) {
8653 nodes[ iNode ] = cast2Node( nIt->next() );
8654 if ( nodes[ iNode++ ] == prevSideNode )
8655 iPrevNode = iNode - 1;
8658 // there are 2 links to check
8663 // loop on links, to be precise, on the second node of links
8664 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8665 const SMDS_MeshNode* n = nodes[ iNode ];
8667 if ( !volume.IsLinked( n, prevSideNode ))
8671 if ( iNode ) // a node before prevSideNode
8672 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8673 else // a node after prevSideNode
8674 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8676 // check if this link was already used
8677 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8678 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8679 if (!isJustChecked &&
8680 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8682 // test a link geometrically
8683 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8684 bool linkIsBetter = false;
8685 double dot = 0.0, dist = 0.0;
8686 if ( searchByDir ) { // choose most co-directed link
8687 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8688 linkIsBetter = ( dot > maxDot );
8690 else { // choose link with the node closest to bordPos
8691 dist = ( nextXYZ - bordPos ).SquareModulus();
8692 linkIsBetter = ( dist < minDist );
8694 if ( linkIsBetter ) {
8703 } // loop on inverse elements of prevSideNode
8706 MESSAGE(" Cant find path by links of the Side 2 ");
8707 return SEW_BAD_SIDE_NODES;
8709 sideNodes.push_back( sideNode );
8710 sideElems.push_back( sideElem );
8711 foundSideLinkIDs.insert ( linkID );
8712 prevSideNode = sideNode;
8714 if ( *nBordIt == theBordLastNode )
8715 searchByDir = false;
8717 // find the next border link to compare with
8718 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8719 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8720 // move to next border node if sideNode is before forward border node (bordPos)
8721 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8722 prevBordNode = *nBordIt;
8724 bordPos = nBordXYZ[ *nBordIt ];
8725 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8726 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8730 while ( sideNode != theSideSecondNode );
8732 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8733 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8734 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8736 } // end nodes search on the side 2
8738 // ============================
8739 // sew the border to the side 2
8740 // ============================
8742 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8743 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8745 TListOfListOfNodes nodeGroupsToMerge;
8746 if ( nbNodes[0] == nbNodes[1] ||
8747 ( theSideIsFreeBorder && !theSideThirdNode)) {
8749 // all nodes are to be merged
8751 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8752 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8753 nIt[0]++, nIt[1]++ )
8755 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8756 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8757 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8762 // insert new nodes into the border and the side to get equal nb of segments
8764 // get normalized parameters of nodes on the borders
8765 //double param[ 2 ][ maxNbNodes ];
8767 param[0] = new double [ maxNbNodes ];
8768 param[1] = new double [ maxNbNodes ];
8770 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8771 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8772 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8773 const SMDS_MeshNode* nPrev = *nIt;
8774 double bordLength = 0;
8775 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8776 const SMDS_MeshNode* nCur = *nIt;
8777 gp_XYZ segment (nCur->X() - nPrev->X(),
8778 nCur->Y() - nPrev->Y(),
8779 nCur->Z() - nPrev->Z());
8780 double segmentLen = segment.Modulus();
8781 bordLength += segmentLen;
8782 param[ iBord ][ iNode ] = bordLength;
8785 // normalize within [0,1]
8786 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8787 param[ iBord ][ iNode ] /= bordLength;
8791 // loop on border segments
8792 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8793 int i[ 2 ] = { 0, 0 };
8794 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8795 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8797 TElemOfNodeListMap insertMap;
8798 TElemOfNodeListMap::iterator insertMapIt;
8800 // key: elem to insert nodes into
8801 // value: 2 nodes to insert between + nodes to be inserted
8803 bool next[ 2 ] = { false, false };
8805 // find min adjacent segment length after sewing
8806 double nextParam = 10., prevParam = 0;
8807 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8808 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8809 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8810 if ( i[ iBord ] > 0 )
8811 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8813 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8814 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8815 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8817 // choose to insert or to merge nodes
8818 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8819 if ( Abs( du ) <= minSegLen * 0.2 ) {
8822 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8823 const SMDS_MeshNode* n0 = *nIt[0];
8824 const SMDS_MeshNode* n1 = *nIt[1];
8825 nodeGroupsToMerge.back().push_back( n1 );
8826 nodeGroupsToMerge.back().push_back( n0 );
8827 // position of node of the border changes due to merge
8828 param[ 0 ][ i[0] ] += du;
8829 // move n1 for the sake of elem shape evaluation during insertion.
8830 // n1 will be removed by MergeNodes() anyway
8831 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8832 next[0] = next[1] = true;
8837 int intoBord = ( du < 0 ) ? 0 : 1;
8838 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8839 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8840 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8841 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8842 if ( intoBord == 1 ) {
8843 // move node of the border to be on a link of elem of the side
8844 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8845 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8846 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8847 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8848 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8850 insertMapIt = insertMap.find( elem );
8851 bool notFound = ( insertMapIt == insertMap.end() );
8852 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8854 // insert into another link of the same element:
8855 // 1. perform insertion into the other link of the elem
8856 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8857 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8858 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8859 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8860 // 2. perform insertion into the link of adjacent faces
8862 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8864 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8868 if (toCreatePolyedrs) {
8869 // perform insertion into the links of adjacent volumes
8870 UpdateVolumes(n12, n22, nodeList);
8872 // 3. find an element appeared on n1 and n2 after the insertion
8873 insertMap.erase( elem );
8874 elem = findAdjacentFace( n1, n2, 0 );
8876 if ( notFound || otherLink ) {
8877 // add element and nodes of the side into the insertMap
8878 insertMapIt = insertMap.insert
8879 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8880 (*insertMapIt).second.push_back( n1 );
8881 (*insertMapIt).second.push_back( n2 );
8883 // add node to be inserted into elem
8884 (*insertMapIt).second.push_back( nIns );
8885 next[ 1 - intoBord ] = true;
8888 // go to the next segment
8889 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8890 if ( next[ iBord ] ) {
8891 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8893 nPrev[ iBord ] = *nIt[ iBord ];
8894 nIt[ iBord ]++; i[ iBord ]++;
8898 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8900 // perform insertion of nodes into elements
8902 for (insertMapIt = insertMap.begin();
8903 insertMapIt != insertMap.end();
8906 const SMDS_MeshElement* elem = (*insertMapIt).first;
8907 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8908 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8909 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8911 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8913 if ( !theSideIsFreeBorder ) {
8914 // look for and insert nodes into the faces adjacent to elem
8916 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8918 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8923 if (toCreatePolyedrs) {
8924 // perform insertion into the links of adjacent volumes
8925 UpdateVolumes(n1, n2, nodeList);
8931 } // end: insert new nodes
8933 MergeNodes ( nodeGroupsToMerge );
8938 //=======================================================================
8939 //function : InsertNodesIntoLink
8940 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8941 // and theBetweenNode2 and split theElement
8942 //=======================================================================
8944 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8945 const SMDS_MeshNode* theBetweenNode1,
8946 const SMDS_MeshNode* theBetweenNode2,
8947 list<const SMDS_MeshNode*>& theNodesToInsert,
8948 const bool toCreatePoly)
8950 if ( theFace->GetType() != SMDSAbs_Face ) return;
8952 // find indices of 2 link nodes and of the rest nodes
8953 int iNode = 0, il1, il2, i3, i4;
8954 il1 = il2 = i3 = i4 = -1;
8955 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8956 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8958 if(theFace->IsQuadratic()) {
8959 const SMDS_VtkFace* F =
8960 dynamic_cast<const SMDS_VtkFace*>(theFace);
8961 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8962 // use special nodes iterator
8963 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8964 while( anIter->more() ) {
8965 const SMDS_MeshNode* n = cast2Node(anIter->next());
8966 if ( n == theBetweenNode1 )
8968 else if ( n == theBetweenNode2 )
8974 nodes[ iNode++ ] = n;
8978 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8979 while ( nodeIt->more() ) {
8980 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8981 if ( n == theBetweenNode1 )
8983 else if ( n == theBetweenNode2 )
8989 nodes[ iNode++ ] = n;
8992 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8995 // arrange link nodes to go one after another regarding the face orientation
8996 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8997 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
9002 aNodesToInsert.reverse();
9004 // check that not link nodes of a quadrangles are in good order
9005 int nbFaceNodes = theFace->NbNodes();
9006 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
9012 if (toCreatePoly || theFace->IsPoly()) {
9015 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
9017 // add nodes of face up to first node of link
9020 if(theFace->IsQuadratic()) {
9021 const SMDS_VtkFace* F =
9022 dynamic_cast<const SMDS_VtkFace*>(theFace);
9023 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9024 // use special nodes iterator
9025 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9026 while( anIter->more() && !isFLN ) {
9027 const SMDS_MeshNode* n = cast2Node(anIter->next());
9028 poly_nodes[iNode++] = n;
9029 if (n == nodes[il1]) {
9033 // add nodes to insert
9034 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9035 for (; nIt != aNodesToInsert.end(); nIt++) {
9036 poly_nodes[iNode++] = *nIt;
9038 // add nodes of face starting from last node of link
9039 while ( anIter->more() ) {
9040 poly_nodes[iNode++] = cast2Node(anIter->next());
9044 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9045 while ( nodeIt->more() && !isFLN ) {
9046 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9047 poly_nodes[iNode++] = n;
9048 if (n == nodes[il1]) {
9052 // add nodes to insert
9053 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9054 for (; nIt != aNodesToInsert.end(); nIt++) {
9055 poly_nodes[iNode++] = *nIt;
9057 // add nodes of face starting from last node of link
9058 while ( nodeIt->more() ) {
9059 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9060 poly_nodes[iNode++] = n;
9064 // edit or replace the face
9065 SMESHDS_Mesh *aMesh = GetMeshDS();
9067 if (theFace->IsPoly()) {
9068 aMesh->ChangePolygonNodes(theFace, poly_nodes);
9071 int aShapeId = FindShape( theFace );
9073 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
9074 myLastCreatedElems.Append(newElem);
9075 if ( aShapeId && newElem )
9076 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9078 aMesh->RemoveElement(theFace);
9083 SMESHDS_Mesh *aMesh = GetMeshDS();
9084 if( !theFace->IsQuadratic() ) {
9086 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
9087 int nbLinkNodes = 2 + aNodesToInsert.size();
9088 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
9089 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
9090 linkNodes[ 0 ] = nodes[ il1 ];
9091 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
9092 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9093 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9094 linkNodes[ iNode++ ] = *nIt;
9096 // decide how to split a quadrangle: compare possible variants
9097 // and choose which of splits to be a quadrangle
9098 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
9099 if ( nbFaceNodes == 3 ) {
9100 iBestQuad = nbSplits;
9103 else if ( nbFaceNodes == 4 ) {
9104 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
9105 double aBestRate = DBL_MAX;
9106 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
9108 double aBadRate = 0;
9109 // evaluate elements quality
9110 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
9111 if ( iSplit == iQuad ) {
9112 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
9116 aBadRate += getBadRate( &quad, aCrit );
9119 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
9121 nodes[ iSplit < iQuad ? i4 : i3 ]);
9122 aBadRate += getBadRate( &tria, aCrit );
9126 if ( aBadRate < aBestRate ) {
9128 aBestRate = aBadRate;
9133 // create new elements
9134 int aShapeId = FindShape( theFace );
9137 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
9138 SMDS_MeshElement* newElem = 0;
9139 if ( iSplit == iBestQuad )
9140 newElem = aMesh->AddFace (linkNodes[ i1++ ],
9145 newElem = aMesh->AddFace (linkNodes[ i1++ ],
9147 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9148 myLastCreatedElems.Append(newElem);
9149 if ( aShapeId && newElem )
9150 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9153 // change nodes of theFace
9154 const SMDS_MeshNode* newNodes[ 4 ];
9155 newNodes[ 0 ] = linkNodes[ i1 ];
9156 newNodes[ 1 ] = linkNodes[ i2 ];
9157 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9158 newNodes[ 3 ] = nodes[ i4 ];
9159 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9160 const SMDS_MeshElement* newElem = 0;
9161 if (iSplit == iBestQuad)
9162 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9164 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9165 myLastCreatedElems.Append(newElem);
9166 if ( aShapeId && newElem )
9167 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9168 } // end if(!theFace->IsQuadratic())
9169 else { // theFace is quadratic
9170 // we have to split theFace on simple triangles and one simple quadrangle
9172 int nbshift = tmp*2;
9173 // shift nodes in nodes[] by nbshift
9175 for(i=0; i<nbshift; i++) {
9176 const SMDS_MeshNode* n = nodes[0];
9177 for(j=0; j<nbFaceNodes-1; j++) {
9178 nodes[j] = nodes[j+1];
9180 nodes[nbFaceNodes-1] = n;
9182 il1 = il1 - nbshift;
9183 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9184 // n0 n1 n2 n0 n1 n2
9185 // +-----+-----+ +-----+-----+
9194 // create new elements
9195 int aShapeId = FindShape( theFace );
9198 if(nbFaceNodes==6) { // quadratic triangle
9199 SMDS_MeshElement* newElem =
9200 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9201 myLastCreatedElems.Append(newElem);
9202 if ( aShapeId && newElem )
9203 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9204 if(theFace->IsMediumNode(nodes[il1])) {
9205 // create quadrangle
9206 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9207 myLastCreatedElems.Append(newElem);
9208 if ( aShapeId && newElem )
9209 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9215 // create quadrangle
9216 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9217 myLastCreatedElems.Append(newElem);
9218 if ( aShapeId && newElem )
9219 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9225 else { // nbFaceNodes==8 - quadratic quadrangle
9226 SMDS_MeshElement* newElem =
9227 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9228 myLastCreatedElems.Append(newElem);
9229 if ( aShapeId && newElem )
9230 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9231 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9232 myLastCreatedElems.Append(newElem);
9233 if ( aShapeId && newElem )
9234 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9235 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9236 myLastCreatedElems.Append(newElem);
9237 if ( aShapeId && newElem )
9238 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9239 if(theFace->IsMediumNode(nodes[il1])) {
9240 // create quadrangle
9241 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9242 myLastCreatedElems.Append(newElem);
9243 if ( aShapeId && newElem )
9244 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9250 // create quadrangle
9251 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9252 myLastCreatedElems.Append(newElem);
9253 if ( aShapeId && newElem )
9254 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9260 // create needed triangles using n1,n2,n3 and inserted nodes
9261 int nbn = 2 + aNodesToInsert.size();
9262 //const SMDS_MeshNode* aNodes[nbn];
9263 vector<const SMDS_MeshNode*> aNodes(nbn);
9264 aNodes[0] = nodes[n1];
9265 aNodes[nbn-1] = nodes[n2];
9266 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9267 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9268 aNodes[iNode++] = *nIt;
9270 for(i=1; i<nbn; i++) {
9271 SMDS_MeshElement* newElem =
9272 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9273 myLastCreatedElems.Append(newElem);
9274 if ( aShapeId && newElem )
9275 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9279 aMesh->RemoveElement(theFace);
9282 //=======================================================================
9283 //function : UpdateVolumes
9285 //=======================================================================
9286 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9287 const SMDS_MeshNode* theBetweenNode2,
9288 list<const SMDS_MeshNode*>& theNodesToInsert)
9290 myLastCreatedElems.Clear();
9291 myLastCreatedNodes.Clear();
9293 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9294 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9295 const SMDS_MeshElement* elem = invElemIt->next();
9297 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9298 SMDS_VolumeTool aVolume (elem);
9299 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9302 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9303 int iface, nbFaces = aVolume.NbFaces();
9304 vector<const SMDS_MeshNode *> poly_nodes;
9305 vector<int> quantities (nbFaces);
9307 for (iface = 0; iface < nbFaces; iface++) {
9308 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9309 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9310 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9312 for (int inode = 0; inode < nbFaceNodes; inode++) {
9313 poly_nodes.push_back(faceNodes[inode]);
9315 if (nbInserted == 0) {
9316 if (faceNodes[inode] == theBetweenNode1) {
9317 if (faceNodes[inode + 1] == theBetweenNode2) {
9318 nbInserted = theNodesToInsert.size();
9320 // add nodes to insert
9321 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9322 for (; nIt != theNodesToInsert.end(); nIt++) {
9323 poly_nodes.push_back(*nIt);
9327 else if (faceNodes[inode] == theBetweenNode2) {
9328 if (faceNodes[inode + 1] == theBetweenNode1) {
9329 nbInserted = theNodesToInsert.size();
9331 // add nodes to insert in reversed order
9332 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9334 for (; nIt != theNodesToInsert.begin(); nIt--) {
9335 poly_nodes.push_back(*nIt);
9337 poly_nodes.push_back(*nIt);
9344 quantities[iface] = nbFaceNodes + nbInserted;
9347 // Replace or update the volume
9348 SMESHDS_Mesh *aMesh = GetMeshDS();
9350 if (elem->IsPoly()) {
9351 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9355 int aShapeId = FindShape( elem );
9357 SMDS_MeshElement* newElem =
9358 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9359 myLastCreatedElems.Append(newElem);
9360 if (aShapeId && newElem)
9361 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9363 aMesh->RemoveElement(elem);
9370 //================================================================================
9372 * \brief Transform any volume into data of SMDSEntity_Polyhedra
9374 //================================================================================
9376 void volumeToPolyhedron( const SMDS_MeshElement* elem,
9377 vector<const SMDS_MeshNode *> & nodes,
9378 vector<int> & nbNodeInFaces )
9381 nbNodeInFaces.clear();
9382 SMDS_VolumeTool vTool ( elem );
9383 for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9385 const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9386 nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9387 nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9392 //=======================================================================
9394 * \brief Convert elements contained in a submesh to quadratic
9395 * \return int - nb of checked elements
9397 //=======================================================================
9399 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9400 SMESH_MesherHelper& theHelper,
9401 const bool theForce3d)
9404 if( !theSm ) return nbElem;
9406 vector<int> nbNodeInFaces;
9407 vector<const SMDS_MeshNode *> nodes;
9408 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9409 while(ElemItr->more())
9412 const SMDS_MeshElement* elem = ElemItr->next();
9413 if( !elem || elem->IsQuadratic() ) continue;
9415 // get elem data needed to re-create it
9417 const int id = elem->GetID();
9418 const int nbNodes = elem->NbNodes();
9419 const SMDSAbs_ElementType aType = elem->GetType();
9420 const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
9421 nodes.assign(elem->begin_nodes(), elem->end_nodes());
9422 if ( aGeomType == SMDSEntity_Polyhedra )
9423 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9424 else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
9425 volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9427 // remove a linear element
9428 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9430 const SMDS_MeshElement* NewElem = 0;
9436 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9444 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9447 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9450 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9455 case SMDSAbs_Volume :
9459 case SMDSEntity_Tetra:
9460 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9462 case SMDSEntity_Pyramid:
9463 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9465 case SMDSEntity_Penta:
9466 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9468 case SMDSEntity_Hexa:
9469 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9470 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9472 case SMDSEntity_Hexagonal_Prism:
9474 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9481 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9483 theSm->AddElement( NewElem );
9488 //=======================================================================
9489 //function : ConvertToQuadratic
9491 //=======================================================================
9493 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9495 SMESHDS_Mesh* meshDS = GetMeshDS();
9497 SMESH_MesherHelper aHelper(*myMesh);
9498 aHelper.SetIsQuadratic( true );
9500 int nbCheckedElems = 0;
9501 if ( myMesh->HasShapeToMesh() )
9503 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9505 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9506 while ( smIt->more() ) {
9507 SMESH_subMesh* sm = smIt->next();
9508 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9509 aHelper.SetSubShape( sm->GetSubShape() );
9510 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9515 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9516 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9518 SMESHDS_SubMesh *smDS = 0;
9519 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9520 while(aEdgeItr->more())
9522 const SMDS_MeshEdge* edge = aEdgeItr->next();
9523 if(edge && !edge->IsQuadratic())
9525 int id = edge->GetID();
9526 //MESSAGE("edge->GetID() " << id);
9527 const SMDS_MeshNode* n1 = edge->GetNode(0);
9528 const SMDS_MeshNode* n2 = edge->GetNode(1);
9530 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9532 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9533 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9536 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9537 while(aFaceItr->more())
9539 const SMDS_MeshFace* face = aFaceItr->next();
9540 if(!face || face->IsQuadratic() ) continue;
9542 const int id = face->GetID();
9543 const SMDSAbs_EntityType type = face->GetEntityType();
9544 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9546 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9548 SMDS_MeshFace * NewFace = 0;
9551 case SMDSEntity_Triangle:
9552 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9554 case SMDSEntity_Quadrangle:
9555 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9558 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9560 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9562 vector<int> nbNodeInFaces;
9563 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9564 while(aVolumeItr->more())
9566 const SMDS_MeshVolume* volume = aVolumeItr->next();
9567 if(!volume || volume->IsQuadratic() ) continue;
9569 const int id = volume->GetID();
9570 const SMDSAbs_EntityType type = volume->GetEntityType();
9571 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9572 if ( type == SMDSEntity_Polyhedra )
9573 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9574 else if ( type == SMDSEntity_Hexagonal_Prism )
9575 volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9577 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9579 SMDS_MeshVolume * NewVolume = 0;
9582 case SMDSEntity_Tetra:
9583 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
9585 case SMDSEntity_Hexa:
9586 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9587 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9589 case SMDSEntity_Pyramid:
9590 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9591 nodes[3], nodes[4], id, theForce3d);
9593 case SMDSEntity_Penta:
9594 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9595 nodes[3], nodes[4], nodes[5], id, theForce3d);
9597 case SMDSEntity_Hexagonal_Prism:
9599 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9601 ReplaceElemInGroups(volume, NewVolume, meshDS);
9606 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9607 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9608 aHelper.FixQuadraticElements();
9612 //================================================================================
9614 * \brief Makes given elements quadratic
9615 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9616 * \param theElements - elements to make quadratic
9618 //================================================================================
9620 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9621 TIDSortedElemSet& theElements)
9623 if ( theElements.empty() ) return;
9625 // we believe that all theElements are of the same type
9626 const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9628 // get all nodes shared by theElements
9629 TIDSortedNodeSet allNodes;
9630 TIDSortedElemSet::iterator eIt = theElements.begin();
9631 for ( ; eIt != theElements.end(); ++eIt )
9632 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9634 // complete theElements with elements of lower dim whose all nodes are in allNodes
9636 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9637 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9638 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9639 for ( ; nIt != allNodes.end(); ++nIt )
9641 const SMDS_MeshNode* n = *nIt;
9642 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9643 while ( invIt->more() )
9645 const SMDS_MeshElement* e = invIt->next();
9646 if ( e->IsQuadratic() )
9648 quadAdjacentElems[ e->GetType() ].insert( e );
9651 if ( e->GetType() >= elemType )
9653 continue; // same type of more complex linear element
9656 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9657 continue; // e is already checked
9661 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9662 while ( nodeIt->more() && allIn )
9663 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9665 theElements.insert(e );
9669 SMESH_MesherHelper helper(*myMesh);
9670 helper.SetIsQuadratic( true );
9672 // add links of quadratic adjacent elements to the helper
9674 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9675 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9676 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9678 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9680 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9681 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9682 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9684 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9686 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9687 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9688 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9690 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9693 // make quadratic elements instead of linear ones
9695 SMESHDS_Mesh* meshDS = GetMeshDS();
9696 SMESHDS_SubMesh* smDS = 0;
9697 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9699 const SMDS_MeshElement* elem = *eIt;
9700 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9703 const int id = elem->GetID();
9704 const SMDSAbs_ElementType type = elem->GetType();
9705 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9707 if ( !smDS || !smDS->Contains( elem ))
9708 smDS = meshDS->MeshElements( elem->getshapeId() );
9709 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9711 SMDS_MeshElement * newElem = 0;
9712 switch( nodes.size() )
9714 case 4: // cases for most frequently used element types go first (for optimization)
9715 if ( type == SMDSAbs_Volume )
9716 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9718 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9721 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9722 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9725 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9728 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9731 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9732 nodes[4], id, theForce3d);
9735 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9736 nodes[4], nodes[5], id, theForce3d);
9740 ReplaceElemInGroups( elem, newElem, meshDS);
9741 if( newElem && smDS )
9742 smDS->AddElement( newElem );
9745 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9746 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9747 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9748 helper.FixQuadraticElements();
9752 //=======================================================================
9754 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9755 * \return int - nb of checked elements
9757 //=======================================================================
9759 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9760 SMDS_ElemIteratorPtr theItr,
9761 const int theShapeID)
9764 SMESHDS_Mesh* meshDS = GetMeshDS();
9766 while( theItr->more() )
9768 const SMDS_MeshElement* elem = theItr->next();
9770 if( elem && elem->IsQuadratic())
9772 int id = elem->GetID();
9773 int nbCornerNodes = elem->NbCornerNodes();
9774 SMDSAbs_ElementType aType = elem->GetType();
9776 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9778 //remove a quadratic element
9779 if ( !theSm || !theSm->Contains( elem ))
9780 theSm = meshDS->MeshElements( elem->getshapeId() );
9781 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9783 // remove medium nodes
9784 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9785 if ( nodes[i]->NbInverseElements() == 0 )
9786 meshDS->RemoveFreeNode( nodes[i], theSm );
9788 // add a linear element
9789 nodes.resize( nbCornerNodes );
9790 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9791 ReplaceElemInGroups(elem, newElem, meshDS);
9792 if( theSm && newElem )
9793 theSm->AddElement( newElem );
9799 //=======================================================================
9800 //function : ConvertFromQuadratic
9802 //=======================================================================
9804 bool SMESH_MeshEditor::ConvertFromQuadratic()
9806 int nbCheckedElems = 0;
9807 if ( myMesh->HasShapeToMesh() )
9809 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9811 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9812 while ( smIt->more() ) {
9813 SMESH_subMesh* sm = smIt->next();
9814 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9815 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9821 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9822 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9824 SMESHDS_SubMesh *aSM = 0;
9825 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9833 //================================================================================
9835 * \brief Return true if all medium nodes of the element are in the node set
9837 //================================================================================
9839 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9841 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9842 if ( !nodeSet.count( elem->GetNode(i) ))
9848 //================================================================================
9850 * \brief Makes given elements linear
9852 //================================================================================
9854 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9856 if ( theElements.empty() ) return;
9858 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9859 set<int> mediumNodeIDs;
9860 TIDSortedElemSet::iterator eIt = theElements.begin();
9861 for ( ; eIt != theElements.end(); ++eIt )
9863 const SMDS_MeshElement* e = *eIt;
9864 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9865 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9868 // replace given elements by linear ones
9869 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9870 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9871 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9873 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9874 // except those elements sharing medium nodes of quadratic element whose medium nodes
9875 // are not all in mediumNodeIDs
9877 // get remaining medium nodes
9878 TIDSortedNodeSet mediumNodes;
9879 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9880 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9881 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9882 mediumNodes.insert( mediumNodes.end(), n );
9884 // find more quadratic elements to convert
9885 TIDSortedElemSet moreElemsToConvert;
9886 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9887 for ( ; nIt != mediumNodes.end(); ++nIt )
9889 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9890 while ( invIt->more() )
9892 const SMDS_MeshElement* e = invIt->next();
9893 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9895 // find a more complex element including e and
9896 // whose medium nodes are not in mediumNodes
9897 bool complexFound = false;
9898 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9900 SMDS_ElemIteratorPtr invIt2 =
9901 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9902 while ( invIt2->more() )
9904 const SMDS_MeshElement* eComplex = invIt2->next();
9905 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9907 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9908 if ( nbCommonNodes == e->NbNodes())
9910 complexFound = true;
9911 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9917 if ( !complexFound )
9918 moreElemsToConvert.insert( e );
9922 elemIt = SMDS_ElemIteratorPtr
9923 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9924 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9927 //=======================================================================
9928 //function : SewSideElements
9930 //=======================================================================
9932 SMESH_MeshEditor::Sew_Error
9933 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9934 TIDSortedElemSet& theSide2,
9935 const SMDS_MeshNode* theFirstNode1,
9936 const SMDS_MeshNode* theFirstNode2,
9937 const SMDS_MeshNode* theSecondNode1,
9938 const SMDS_MeshNode* theSecondNode2)
9940 myLastCreatedElems.Clear();
9941 myLastCreatedNodes.Clear();
9943 MESSAGE ("::::SewSideElements()");
9944 if ( theSide1.size() != theSide2.size() )
9945 return SEW_DIFF_NB_OF_ELEMENTS;
9947 Sew_Error aResult = SEW_OK;
9949 // 1. Build set of faces representing each side
9950 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9951 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9953 // =======================================================================
9954 // 1. Build set of faces representing each side:
9955 // =======================================================================
9956 // a. build set of nodes belonging to faces
9957 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9958 // c. create temporary faces representing side of volumes if correspondent
9959 // face does not exist
9961 SMESHDS_Mesh* aMesh = GetMeshDS();
9962 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9963 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9964 TIDSortedElemSet faceSet1, faceSet2;
9965 set<const SMDS_MeshElement*> volSet1, volSet2;
9966 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9967 TIDSortedElemSet * faceSetPtr[] = { &faceSet1, &faceSet2 };
9968 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9969 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9970 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9971 int iSide, iFace, iNode;
9973 list<const SMDS_MeshElement* > tempFaceList;
9974 for ( iSide = 0; iSide < 2; iSide++ ) {
9975 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9976 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9977 TIDSortedElemSet * faceSet = faceSetPtr[ iSide ];
9978 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9979 set<const SMDS_MeshElement*>::iterator vIt;
9980 TIDSortedElemSet::iterator eIt;
9981 set<const SMDS_MeshNode*>::iterator nIt;
9983 // check that given nodes belong to given elements
9984 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9985 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9986 int firstIndex = -1, secondIndex = -1;
9987 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9988 const SMDS_MeshElement* elem = *eIt;
9989 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9990 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9991 if ( firstIndex > -1 && secondIndex > -1 ) break;
9993 if ( firstIndex < 0 || secondIndex < 0 ) {
9994 // we can simply return until temporary faces created
9995 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9998 // -----------------------------------------------------------
9999 // 1a. Collect nodes of existing faces
10000 // and build set of face nodes in order to detect missing
10001 // faces corresponding to sides of volumes
10002 // -----------------------------------------------------------
10004 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
10006 // loop on the given element of a side
10007 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
10008 //const SMDS_MeshElement* elem = *eIt;
10009 const SMDS_MeshElement* elem = *eIt;
10010 if ( elem->GetType() == SMDSAbs_Face ) {
10011 faceSet->insert( elem );
10012 set <const SMDS_MeshNode*> faceNodeSet;
10013 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
10014 while ( nodeIt->more() ) {
10015 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10016 nodeSet->insert( n );
10017 faceNodeSet.insert( n );
10019 setOfFaceNodeSet.insert( faceNodeSet );
10021 else if ( elem->GetType() == SMDSAbs_Volume )
10022 volSet->insert( elem );
10024 // ------------------------------------------------------------------------------
10025 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
10026 // ------------------------------------------------------------------------------
10028 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10029 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10030 while ( fIt->more() ) { // loop on faces sharing a node
10031 const SMDS_MeshElement* f = fIt->next();
10032 if ( faceSet->find( f ) == faceSet->end() ) {
10033 // check if all nodes are in nodeSet and
10034 // complete setOfFaceNodeSet if they are
10035 set <const SMDS_MeshNode*> faceNodeSet;
10036 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10037 bool allInSet = true;
10038 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10039 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10040 if ( nodeSet->find( n ) == nodeSet->end() )
10043 faceNodeSet.insert( n );
10046 faceSet->insert( f );
10047 setOfFaceNodeSet.insert( faceNodeSet );
10053 // -------------------------------------------------------------------------
10054 // 1c. Create temporary faces representing sides of volumes if correspondent
10055 // face does not exist
10056 // -------------------------------------------------------------------------
10058 if ( !volSet->empty() ) {
10059 //int nodeSetSize = nodeSet->size();
10061 // loop on given volumes
10062 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
10063 SMDS_VolumeTool vol (*vIt);
10064 // loop on volume faces: find free faces
10065 // --------------------------------------
10066 list<const SMDS_MeshElement* > freeFaceList;
10067 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
10068 if ( !vol.IsFreeFace( iFace ))
10070 // check if there is already a face with same nodes in a face set
10071 const SMDS_MeshElement* aFreeFace = 0;
10072 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
10073 int nbNodes = vol.NbFaceNodes( iFace );
10074 set <const SMDS_MeshNode*> faceNodeSet;
10075 vol.GetFaceNodes( iFace, faceNodeSet );
10076 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
10078 // no such a face is given but it still can exist, check it
10079 vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
10080 aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
10082 if ( !aFreeFace ) {
10083 // create a temporary face
10084 if ( nbNodes == 3 ) {
10085 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
10086 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
10088 else if ( nbNodes == 4 ) {
10089 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10090 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10093 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10094 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
10095 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
10098 tempFaceList.push_back( aFreeFace );
10102 freeFaceList.push_back( aFreeFace );
10104 } // loop on faces of a volume
10106 // choose one of several free faces of a volume
10107 // --------------------------------------------
10108 if ( freeFaceList.size() > 1 ) {
10109 // choose a face having max nb of nodes shared by other elems of a side
10110 int maxNbNodes = -1;
10111 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
10112 while ( fIt != freeFaceList.end() ) { // loop on free faces
10113 int nbSharedNodes = 0;
10114 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10115 while ( nodeIt->more() ) { // loop on free face nodes
10116 const SMDS_MeshNode* n =
10117 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10118 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
10119 while ( invElemIt->more() ) {
10120 const SMDS_MeshElement* e = invElemIt->next();
10121 nbSharedNodes += faceSet->count( e );
10122 nbSharedNodes += elemSet->count( e );
10125 if ( nbSharedNodes > maxNbNodes ) {
10126 maxNbNodes = nbSharedNodes;
10127 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10129 else if ( nbSharedNodes == maxNbNodes ) {
10133 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
10136 if ( freeFaceList.size() > 1 )
10138 // could not choose one face, use another way
10139 // choose a face most close to the bary center of the opposite side
10140 gp_XYZ aBC( 0., 0., 0. );
10141 set <const SMDS_MeshNode*> addedNodes;
10142 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
10143 eIt = elemSet2->begin();
10144 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
10145 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
10146 while ( nodeIt->more() ) { // loop on free face nodes
10147 const SMDS_MeshNode* n =
10148 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10149 if ( addedNodes.insert( n ).second )
10150 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
10153 aBC /= addedNodes.size();
10154 double minDist = DBL_MAX;
10155 fIt = freeFaceList.begin();
10156 while ( fIt != freeFaceList.end() ) { // loop on free faces
10158 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10159 while ( nodeIt->more() ) { // loop on free face nodes
10160 const SMDS_MeshNode* n =
10161 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10162 gp_XYZ p( n->X(),n->Y(),n->Z() );
10163 dist += ( aBC - p ).SquareModulus();
10165 if ( dist < minDist ) {
10167 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10170 fIt = freeFaceList.erase( fIt++ );
10173 } // choose one of several free faces of a volume
10175 if ( freeFaceList.size() == 1 ) {
10176 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10177 faceSet->insert( aFreeFace );
10178 // complete a node set with nodes of a found free face
10179 // for ( iNode = 0; iNode < ; iNode++ )
10180 // nodeSet->insert( fNodes[ iNode ] );
10183 } // loop on volumes of a side
10185 // // complete a set of faces if new nodes in a nodeSet appeared
10186 // // ----------------------------------------------------------
10187 // if ( nodeSetSize != nodeSet->size() ) {
10188 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10189 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10190 // while ( fIt->more() ) { // loop on faces sharing a node
10191 // const SMDS_MeshElement* f = fIt->next();
10192 // if ( faceSet->find( f ) == faceSet->end() ) {
10193 // // check if all nodes are in nodeSet and
10194 // // complete setOfFaceNodeSet if they are
10195 // set <const SMDS_MeshNode*> faceNodeSet;
10196 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10197 // bool allInSet = true;
10198 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10199 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10200 // if ( nodeSet->find( n ) == nodeSet->end() )
10201 // allInSet = false;
10203 // faceNodeSet.insert( n );
10205 // if ( allInSet ) {
10206 // faceSet->insert( f );
10207 // setOfFaceNodeSet.insert( faceNodeSet );
10213 } // Create temporary faces, if there are volumes given
10216 if ( faceSet1.size() != faceSet2.size() ) {
10217 // delete temporary faces: they are in reverseElements of actual nodes
10218 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10219 // while ( tmpFaceIt->more() )
10220 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10221 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10222 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10223 // aMesh->RemoveElement(*tmpFaceIt);
10224 MESSAGE("Diff nb of faces");
10225 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10228 // ============================================================
10229 // 2. Find nodes to merge:
10230 // bind a node to remove to a node to put instead
10231 // ============================================================
10233 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10234 if ( theFirstNode1 != theFirstNode2 )
10235 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10236 if ( theSecondNode1 != theSecondNode2 )
10237 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10239 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10240 set< long > linkIdSet; // links to process
10241 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10243 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10244 list< NLink > linkList[2];
10245 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10246 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10247 // loop on links in linkList; find faces by links and append links
10248 // of the found faces to linkList
10249 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10250 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
10252 NLink link[] = { *linkIt[0], *linkIt[1] };
10253 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10254 if ( !linkIdSet.count( linkID ) )
10257 // by links, find faces in the face sets,
10258 // and find indices of link nodes in the found faces;
10259 // in a face set, there is only one or no face sharing a link
10260 // ---------------------------------------------------------------
10262 const SMDS_MeshElement* face[] = { 0, 0 };
10263 vector<const SMDS_MeshNode*> fnodes[2];
10264 int iLinkNode[2][2];
10265 TIDSortedElemSet avoidSet;
10266 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10267 const SMDS_MeshNode* n1 = link[iSide].first;
10268 const SMDS_MeshNode* n2 = link[iSide].second;
10269 //cout << "Side " << iSide << " ";
10270 //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
10271 // find a face by two link nodes
10272 face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
10273 &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
10274 if ( face[ iSide ])
10276 //cout << " F " << face[ iSide]->GetID() <<endl;
10277 faceSetPtr[ iSide ]->erase( face[ iSide ]);
10278 // put face nodes to fnodes
10279 if ( face[ iSide ]->IsQuadratic() )
10281 // use interlaced nodes iterator
10282 const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
10283 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10284 SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
10285 while ( nIter->more() )
10286 fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
10290 fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
10291 face[ iSide ]->end_nodes() );
10293 fnodes[ iSide ].push_back( fnodes[ iSide ].front());
10297 // check similarity of elements of the sides
10298 if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10299 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10300 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10301 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10304 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10306 break; // do not return because it's necessary to remove tmp faces
10309 // set nodes to merge
10310 // -------------------
10312 if ( face[0] && face[1] ) {
10313 const int nbNodes = face[0]->NbNodes();
10314 if ( nbNodes != face[1]->NbNodes() ) {
10315 MESSAGE("Diff nb of face nodes");
10316 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10317 break; // do not return because it s necessary to remove tmp faces
10319 bool reverse[] = { false, false }; // order of nodes in the link
10320 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10321 // analyse link orientation in faces
10322 int i1 = iLinkNode[ iSide ][ 0 ];
10323 int i2 = iLinkNode[ iSide ][ 1 ];
10324 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10326 int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
10327 int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
10328 for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
10330 nReplaceMap.insert ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
10331 fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
10334 // add other links of the faces to linkList
10335 // -----------------------------------------
10337 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10338 linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
10339 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10340 if ( !iter_isnew.second ) { // already in a set: no need to process
10341 linkIdSet.erase( iter_isnew.first );
10343 else // new in set == encountered for the first time: add
10345 const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
10346 const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
10347 linkList[0].push_back ( NLink( n1, n2 ));
10348 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10353 if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
10356 } // loop on link lists
10358 if ( aResult == SEW_OK &&
10359 ( //linkIt[0] != linkList[0].end() ||
10360 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10361 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10362 " " << (faceSetPtr[1]->empty()));
10363 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10366 // ====================================================================
10367 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10368 // ====================================================================
10370 // delete temporary faces
10371 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10372 // while ( tmpFaceIt->more() )
10373 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10374 list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10375 for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10376 aMesh->RemoveElement(*tmpFaceIt);
10378 if ( aResult != SEW_OK)
10381 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10382 // loop on nodes replacement map
10383 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10384 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10385 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10386 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10387 nodeIDsToRemove.push_back( nToRemove->GetID() );
10388 // loop on elements sharing nToRemove
10389 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10390 while ( invElemIt->more() ) {
10391 const SMDS_MeshElement* e = invElemIt->next();
10392 // get a new suite of nodes: make replacement
10393 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10394 vector< const SMDS_MeshNode*> nodes( nbNodes );
10395 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10396 while ( nIt->more() ) {
10397 const SMDS_MeshNode* n =
10398 static_cast<const SMDS_MeshNode*>( nIt->next() );
10399 nnIt = nReplaceMap.find( n );
10400 if ( nnIt != nReplaceMap.end() ) {
10402 n = (*nnIt).second;
10406 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10407 // elemIDsToRemove.push_back( e->GetID() );
10411 SMDSAbs_ElementType etyp = e->GetType();
10412 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10415 myLastCreatedElems.Append(newElem);
10416 AddToSameGroups(newElem, e, aMesh);
10417 int aShapeId = e->getshapeId();
10420 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10423 aMesh->RemoveElement(e);
10428 Remove( nodeIDsToRemove, true );
10433 //================================================================================
10435 * \brief Find corresponding nodes in two sets of faces
10436 * \param theSide1 - first face set
10437 * \param theSide2 - second first face
10438 * \param theFirstNode1 - a boundary node of set 1
10439 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10440 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10441 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10442 * \param nReplaceMap - output map of corresponding nodes
10443 * \return bool - is a success or not
10445 //================================================================================
10448 //#define DEBUG_MATCHING_NODES
10451 SMESH_MeshEditor::Sew_Error
10452 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10453 set<const SMDS_MeshElement*>& theSide2,
10454 const SMDS_MeshNode* theFirstNode1,
10455 const SMDS_MeshNode* theFirstNode2,
10456 const SMDS_MeshNode* theSecondNode1,
10457 const SMDS_MeshNode* theSecondNode2,
10458 TNodeNodeMap & nReplaceMap)
10460 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10462 nReplaceMap.clear();
10463 if ( theFirstNode1 != theFirstNode2 )
10464 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10465 if ( theSecondNode1 != theSecondNode2 )
10466 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10468 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10469 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10471 list< NLink > linkList[2];
10472 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10473 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10475 // loop on links in linkList; find faces by links and append links
10476 // of the found faces to linkList
10477 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10478 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10479 NLink link[] = { *linkIt[0], *linkIt[1] };
10480 if ( linkSet.find( link[0] ) == linkSet.end() )
10483 // by links, find faces in the face sets,
10484 // and find indices of link nodes in the found faces;
10485 // in a face set, there is only one or no face sharing a link
10486 // ---------------------------------------------------------------
10488 const SMDS_MeshElement* face[] = { 0, 0 };
10489 list<const SMDS_MeshNode*> notLinkNodes[2];
10490 //bool reverse[] = { false, false }; // order of notLinkNodes
10492 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10494 const SMDS_MeshNode* n1 = link[iSide].first;
10495 const SMDS_MeshNode* n2 = link[iSide].second;
10496 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10497 set< const SMDS_MeshElement* > facesOfNode1;
10498 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10500 // during a loop of the first node, we find all faces around n1,
10501 // during a loop of the second node, we find one face sharing both n1 and n2
10502 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10503 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10504 while ( fIt->more() ) { // loop on faces sharing a node
10505 const SMDS_MeshElement* f = fIt->next();
10506 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10507 ! facesOfNode1.insert( f ).second ) // f encounters twice
10509 if ( face[ iSide ] ) {
10510 MESSAGE( "2 faces per link " );
10511 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10514 faceSet->erase( f );
10516 // get not link nodes
10517 int nbN = f->NbNodes();
10518 if ( f->IsQuadratic() )
10520 nbNodes[ iSide ] = nbN;
10521 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10522 int i1 = f->GetNodeIndex( n1 );
10523 int i2 = f->GetNodeIndex( n2 );
10524 int iEnd = nbN, iBeg = -1, iDelta = 1;
10525 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10527 std::swap( iEnd, iBeg ); iDelta = -1;
10532 if ( i == iEnd ) i = iBeg + iDelta;
10533 if ( i == i1 ) break;
10534 nodes.push_back ( f->GetNode( i ) );
10540 // check similarity of elements of the sides
10541 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10542 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10543 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10544 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10547 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10551 // set nodes to merge
10552 // -------------------
10554 if ( face[0] && face[1] ) {
10555 if ( nbNodes[0] != nbNodes[1] ) {
10556 MESSAGE("Diff nb of face nodes");
10557 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10559 #ifdef DEBUG_MATCHING_NODES
10560 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10561 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10562 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10564 int nbN = nbNodes[0];
10566 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10567 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10568 for ( int i = 0 ; i < nbN - 2; ++i ) {
10569 #ifdef DEBUG_MATCHING_NODES
10570 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10572 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10576 // add other links of the face 1 to linkList
10577 // -----------------------------------------
10579 const SMDS_MeshElement* f0 = face[0];
10580 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10581 for ( int i = 0; i < nbN; i++ )
10583 const SMDS_MeshNode* n2 = f0->GetNode( i );
10584 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10585 linkSet.insert( SMESH_TLink( n1, n2 ));
10586 if ( !iter_isnew.second ) { // already in a set: no need to process
10587 linkSet.erase( iter_isnew.first );
10589 else // new in set == encountered for the first time: add
10591 #ifdef DEBUG_MATCHING_NODES
10592 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10593 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10595 linkList[0].push_back ( NLink( n1, n2 ));
10596 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10601 } // loop on link lists
10606 //================================================================================
10608 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10609 \param theElems - the list of elements (edges or faces) to be replicated
10610 The nodes for duplication could be found from these elements
10611 \param theNodesNot - list of nodes to NOT replicate
10612 \param theAffectedElems - the list of elements (cells and edges) to which the
10613 replicated nodes should be associated to.
10614 \return TRUE if operation has been completed successfully, FALSE otherwise
10616 //================================================================================
10618 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10619 const TIDSortedElemSet& theNodesNot,
10620 const TIDSortedElemSet& theAffectedElems )
10622 myLastCreatedElems.Clear();
10623 myLastCreatedNodes.Clear();
10625 if ( theElems.size() == 0 )
10628 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10633 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10634 // duplicate elements and nodes
10635 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10636 // replce nodes by duplications
10637 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10641 //================================================================================
10643 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10644 \param theMeshDS - mesh instance
10645 \param theElems - the elements replicated or modified (nodes should be changed)
10646 \param theNodesNot - nodes to NOT replicate
10647 \param theNodeNodeMap - relation of old node to new created node
10648 \param theIsDoubleElem - flag os to replicate element or modify
10649 \return TRUE if operation has been completed successfully, FALSE otherwise
10651 //================================================================================
10653 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10654 const TIDSortedElemSet& theElems,
10655 const TIDSortedElemSet& theNodesNot,
10656 std::map< const SMDS_MeshNode*,
10657 const SMDS_MeshNode* >& theNodeNodeMap,
10658 const bool theIsDoubleElem )
10660 MESSAGE("doubleNodes");
10661 // iterate on through element and duplicate them (by nodes duplication)
10663 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10664 for ( ; elemItr != theElems.end(); ++elemItr )
10666 const SMDS_MeshElement* anElem = *elemItr;
10670 bool isDuplicate = false;
10671 // duplicate nodes to duplicate element
10672 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10673 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10675 while ( anIter->more() )
10678 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10679 SMDS_MeshNode* aNewNode = aCurrNode;
10680 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10681 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10682 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10685 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10686 theNodeNodeMap[ aCurrNode ] = aNewNode;
10687 myLastCreatedNodes.Append( aNewNode );
10689 isDuplicate |= (aCurrNode != aNewNode);
10690 newNodes[ ind++ ] = aNewNode;
10692 if ( !isDuplicate )
10695 if ( theIsDoubleElem )
10696 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10699 MESSAGE("ChangeElementNodes");
10700 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10707 //================================================================================
10709 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10710 \param theNodes - identifiers of nodes to be doubled
10711 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10712 nodes. If list of element identifiers is empty then nodes are doubled but
10713 they not assigned to elements
10714 \return TRUE if operation has been completed successfully, FALSE otherwise
10716 //================================================================================
10718 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10719 const std::list< int >& theListOfModifiedElems )
10721 MESSAGE("DoubleNodes");
10722 myLastCreatedElems.Clear();
10723 myLastCreatedNodes.Clear();
10725 if ( theListOfNodes.size() == 0 )
10728 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10732 // iterate through nodes and duplicate them
10734 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10736 std::list< int >::const_iterator aNodeIter;
10737 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10739 int aCurr = *aNodeIter;
10740 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10746 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10749 anOldNodeToNewNode[ aNode ] = aNewNode;
10750 myLastCreatedNodes.Append( aNewNode );
10754 // Create map of new nodes for modified elements
10756 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10758 std::list< int >::const_iterator anElemIter;
10759 for ( anElemIter = theListOfModifiedElems.begin();
10760 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10762 int aCurr = *anElemIter;
10763 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10767 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10769 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10771 while ( anIter->more() )
10773 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10774 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10776 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10777 aNodeArr[ ind++ ] = aNewNode;
10780 aNodeArr[ ind++ ] = aCurrNode;
10782 anElemToNodes[ anElem ] = aNodeArr;
10785 // Change nodes of elements
10787 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10788 anElemToNodesIter = anElemToNodes.begin();
10789 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10791 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10792 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10795 MESSAGE("ChangeElementNodes");
10796 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10805 //================================================================================
10807 \brief Check if element located inside shape
10808 \return TRUE if IN or ON shape, FALSE otherwise
10810 //================================================================================
10812 template<class Classifier>
10813 bool isInside(const SMDS_MeshElement* theElem,
10814 Classifier& theClassifier,
10815 const double theTol)
10817 gp_XYZ centerXYZ (0, 0, 0);
10818 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10819 while (aNodeItr->more())
10820 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10822 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10823 theClassifier.Perform(aPnt, theTol);
10824 TopAbs_State aState = theClassifier.State();
10825 return (aState == TopAbs_IN || aState == TopAbs_ON );
10828 //================================================================================
10830 * \brief Classifier of the 3D point on the TopoDS_Face
10831 * with interaface suitable for isInside()
10833 //================================================================================
10835 struct _FaceClassifier
10837 Extrema_ExtPS _extremum;
10838 BRepAdaptor_Surface _surface;
10839 TopAbs_State _state;
10841 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10843 _extremum.Initialize( _surface,
10844 _surface.FirstUParameter(), _surface.LastUParameter(),
10845 _surface.FirstVParameter(), _surface.LastVParameter(),
10846 _surface.Tolerance(), _surface.Tolerance() );
10848 void Perform(const gp_Pnt& aPnt, double theTol)
10850 _state = TopAbs_OUT;
10851 _extremum.Perform(aPnt);
10852 if ( _extremum.IsDone() )
10853 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10854 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10855 _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10857 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10860 TopAbs_State State() const
10867 //================================================================================
10869 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10870 \param theElems - group of of elements (edges or faces) to be replicated
10871 \param theNodesNot - group of nodes not to replicate
10872 \param theShape - shape to detect affected elements (element which geometric center
10873 located on or inside shape).
10874 The replicated nodes should be associated to affected elements.
10875 \return TRUE if operation has been completed successfully, FALSE otherwise
10877 //================================================================================
10879 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10880 const TIDSortedElemSet& theNodesNot,
10881 const TopoDS_Shape& theShape )
10883 if ( theShape.IsNull() )
10886 const double aTol = Precision::Confusion();
10887 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10888 auto_ptr<_FaceClassifier> aFaceClassifier;
10889 if ( theShape.ShapeType() == TopAbs_SOLID )
10891 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10892 bsc3d->PerformInfinitePoint(aTol);
10894 else if (theShape.ShapeType() == TopAbs_FACE )
10896 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10899 // iterates on indicated elements and get elements by back references from their nodes
10900 TIDSortedElemSet anAffected;
10901 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10902 for ( ; elemItr != theElems.end(); ++elemItr )
10904 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10908 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10909 while ( nodeItr->more() )
10911 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10912 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10914 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10915 while ( backElemItr->more() )
10917 const SMDS_MeshElement* curElem = backElemItr->next();
10918 if ( curElem && theElems.find(curElem) == theElems.end() &&
10920 isInside( curElem, *bsc3d, aTol ) :
10921 isInside( curElem, *aFaceClassifier, aTol )))
10922 anAffected.insert( curElem );
10926 return DoubleNodes( theElems, theNodesNot, anAffected );
10930 * \brief compute an oriented angle between two planes defined by four points.
10931 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10932 * @param p0 base of the rotation axe
10933 * @param p1 extremity of the rotation axe
10934 * @param g1 belongs to the first plane
10935 * @param g2 belongs to the second plane
10937 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10939 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10940 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10941 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10942 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10943 gp_Vec vref(p0, p1);
10946 gp_Vec n1 = vref.Crossed(v1);
10947 gp_Vec n2 = vref.Crossed(v2);
10948 return n2.AngleWithRef(n1, vref);
10952 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10953 * The list of groups must describe a partition of the mesh volumes.
10954 * The nodes of the internal faces at the boundaries of the groups are doubled.
10955 * In option, the internal faces are replaced by flat elements.
10956 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10957 * The flat elements are stored in groups of volumes.
10958 * @param theElems - list of groups of volumes, where a group of volume is a set of
10959 * SMDS_MeshElements sorted by Id.
10960 * @param createJointElems - if TRUE, create the elements
10961 * @return TRUE if operation has been completed successfully, FALSE otherwise
10963 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10964 bool createJointElems)
10966 MESSAGE("----------------------------------------------");
10967 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10968 MESSAGE("----------------------------------------------");
10970 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10971 meshDS->BuildDownWardConnectivity(true);
10973 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10975 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10976 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10977 // build the list of nodes shared by 2 or more domains, with their domain indexes
10979 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10980 std::map<int,int>celldom; // cell vtkId --> domain
10981 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10982 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10983 faceDomains.clear();
10985 cellDomains.clear();
10986 nodeDomains.clear();
10987 std::map<int,int> emptyMap;
10988 std::set<int> emptySet;
10991 for (int idom = 0; idom < theElems.size(); idom++)
10994 // --- build a map (face to duplicate --> volume to modify)
10995 // with all the faces shared by 2 domains (group of elements)
10996 // and corresponding volume of this domain, for each shared face.
10997 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10999 //MESSAGE("Domain " << idom);
11000 const TIDSortedElemSet& domain = theElems[idom];
11001 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11002 for (; elemItr != domain.end(); ++elemItr)
11004 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11007 int vtkId = anElem->getVtkId();
11008 //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID());
11009 int neighborsVtkIds[NBMAXNEIGHBORS];
11010 int downIds[NBMAXNEIGHBORS];
11011 unsigned char downTypes[NBMAXNEIGHBORS];
11012 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11013 for (int n = 0; n < nbNeighbors; n++)
11015 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11016 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11017 if (! domain.count(elem)) // neighbor is in another domain : face is shared
11019 DownIdType face(downIds[n], downTypes[n]);
11020 if (!faceDomains.count(face))
11021 faceDomains[face] = emptyMap; // create an empty entry for face
11022 if (!faceDomains[face].count(idom))
11024 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11025 celldom[vtkId] = idom;
11026 //MESSAGE(" cell with a border " << vtkId << " domain " << idom);
11033 //MESSAGE("Number of shared faces " << faceDomains.size());
11034 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11036 // --- explore the shared faces domain by domain,
11037 // explore the nodes of the face and see if they belong to a cell in the domain,
11038 // which has only a node or an edge on the border (not a shared face)
11040 for (int idomain = 0; idomain < theElems.size(); idomain++)
11042 //MESSAGE("Domain " << idomain);
11043 const TIDSortedElemSet& domain = theElems[idomain];
11044 itface = faceDomains.begin();
11045 for (; itface != faceDomains.end(); ++itface)
11047 std::map<int, int> domvol = itface->second;
11048 if (!domvol.count(idomain))
11050 DownIdType face = itface->first;
11051 //MESSAGE(" --- face " << face.cellId);
11052 std::set<int> oldNodes;
11054 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11055 std::set<int>::iterator itn = oldNodes.begin();
11056 for (; itn != oldNodes.end(); ++itn)
11059 //MESSAGE(" node " << oldId);
11060 std::set<int> cells;
11062 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11063 for (int i=0; i<l.ncells; i++)
11065 int vtkId = l.cells[i];
11066 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11067 if (!domain.count(anElem))
11069 int vtkType = grid->GetCellType(vtkId);
11070 int downId = grid->CellIdToDownId(vtkId);
11073 MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11074 continue; // not OK at this stage of the algorithm:
11075 //no cells created after BuildDownWardConnectivity
11077 DownIdType aCell(downId, vtkType);
11078 if (celldom.count(vtkId))
11080 cellDomains[aCell][idomain] = vtkId;
11081 celldom[vtkId] = idomain;
11082 //MESSAGE(" cell " << vtkId << " domain " << idomain);
11088 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11089 // for each shared face, get the nodes
11090 // for each node, for each domain of the face, create a clone of the node
11092 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11093 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11094 // the value is the ordered domain ids. (more than 4 domains not taken into account)
11096 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11097 std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
11098 std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
11100 for (int idomain = 0; idomain < theElems.size(); idomain++)
11102 itface = faceDomains.begin();
11103 for (; itface != faceDomains.end(); ++itface)
11105 std::map<int, int> domvol = itface->second;
11106 if (!domvol.count(idomain))
11108 DownIdType face = itface->first;
11109 //MESSAGE(" --- face " << face.cellId);
11110 std::set<int> oldNodes;
11112 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11113 bool isMultipleDetected = false;
11114 std::set<int>::iterator itn = oldNodes.begin();
11115 for (; itn != oldNodes.end(); ++itn)
11118 //MESSAGE(" node " << oldId);
11119 if (!nodeDomains.count(oldId))
11120 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11121 if (nodeDomains[oldId].empty())
11122 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11123 std::map<int, int>::iterator itdom = domvol.begin();
11124 for (; itdom != domvol.end(); ++itdom)
11126 int idom = itdom->first;
11127 //MESSAGE(" domain " << idom);
11128 if (!nodeDomains[oldId].count(idom)) // --- node to clone
11130 if (nodeDomains[oldId].size() >= 2) // a multiple node
11132 vector<int> orderedDoms;
11133 //MESSAGE("multiple node " << oldId);
11134 isMultipleDetected =true;
11135 if (mutipleNodes.count(oldId))
11136 orderedDoms = mutipleNodes[oldId];
11139 map<int,int>::iterator it = nodeDomains[oldId].begin();
11140 for (; it != nodeDomains[oldId].end(); ++it)
11141 orderedDoms.push_back(it->first);
11143 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11144 //stringstream txt;
11145 //for (int i=0; i<orderedDoms.size(); i++)
11146 // txt << orderedDoms[i] << " ";
11147 //MESSAGE("orderedDoms " << txt.str());
11148 mutipleNodes[oldId] = orderedDoms;
11150 double *coords = grid->GetPoint(oldId);
11151 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11152 int newId = newNode->getVtkId();
11153 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11154 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11156 if (nodeDomains[oldId].size() >= 3)
11158 //MESSAGE("confirm multiple node " << oldId);
11159 isMultipleDetected =true;
11163 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11165 //MESSAGE("multiple Nodes detected on a shared face");
11166 int downId = itface->first.cellId;
11167 unsigned char cellType = itface->first.cellType;
11168 // --- shared edge or shared face ?
11169 if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
11172 int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
11173 for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
11174 if (mutipleNodes.count(nodes[i]))
11175 if (!mutipleNodesToFace.count(nodes[i]))
11176 mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
11178 else // shared face (between two volumes)
11180 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11181 const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11182 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11183 for (int ie =0; ie < nbEdges; ie++)
11186 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11187 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11189 vector<int> vn0 = mutipleNodes[nodes[0]];
11190 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11191 sort( vn0.begin(), vn0.end() );
11192 sort( vn1.begin(), vn1.end() );
11195 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11196 double *coords = grid->GetPoint(nodes[0]);
11197 gp_Pnt p0(coords[0], coords[1], coords[2]);
11198 coords = grid->GetPoint(nodes[nbNodes - 1]);
11199 gp_Pnt p1(coords[0], coords[1], coords[2]);
11201 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11202 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11203 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11204 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11205 for (int id=0; id < vn0.size(); id++)
11207 int idom = vn0[id];
11208 for (int ivol=0; ivol<nbvol; ivol++)
11210 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11211 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11212 if (theElems[idom].count(elem))
11214 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11215 domvol[idom] = svol;
11216 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11218 vtkIdType npts = 0;
11219 vtkIdType* pts = 0;
11220 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11221 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11224 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11225 angleDom[idom] = 0;
11229 gp_Pnt g(values[0], values[1], values[2]);
11230 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11231 //MESSAGE(" angle=" << angleDom[idom]);
11237 map<double, int> sortedDom; // sort domains by angle
11238 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11239 sortedDom[ia->second] = ia->first;
11240 vector<int> vnodes;
11242 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11244 vdom.push_back(ib->second);
11245 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11247 for (int ino = 0; ino < nbNodes; ino++)
11248 vnodes.push_back(nodes[ino]);
11249 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11258 // --- iterate on shared faces (volumes to modify, face to extrude)
11259 // get node id's of the face (id SMDS = id VTK)
11260 // create flat element with old and new nodes if requested
11262 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11263 // (domain1 X domain2) = domain1 + MAXINT*domain2
11265 std::map<int, std::map<long,int> > nodeQuadDomains;
11266 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11268 if (createJointElems)
11270 itface = faceDomains.begin();
11271 for (; itface != faceDomains.end(); ++itface)
11273 DownIdType face = itface->first;
11274 std::set<int> oldNodes;
11275 std::set<int>::iterator itn;
11277 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11279 std::map<int, int> domvol = itface->second;
11280 std::map<int, int>::iterator itdom = domvol.begin();
11281 int dom1 = itdom->first;
11282 int vtkVolId = itdom->second;
11284 int dom2 = itdom->first;
11285 SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11287 stringstream grpname;
11290 grpname << dom1 << "_" << dom2;
11292 grpname << dom2 << "_" << dom1;
11294 string namegrp = grpname.str();
11295 if (!mapOfJunctionGroups.count(namegrp))
11296 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
11297 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11299 sgrp->Add(vol->GetID());
11303 // --- create volumes on multiple domain intersection if requested
11304 // iterate on mutipleNodesToFace
11305 // iterate on edgesMultiDomains
11307 if (createJointElems)
11309 // --- iterate on mutipleNodesToFace
11311 std::map<int, std::vector<int> >::iterator itn = mutipleNodesToFace.begin();
11312 for (; itn != mutipleNodesToFace.end(); ++itn)
11314 int node = itn->first;
11315 vector<int> orderDom = itn->second;
11316 vector<vtkIdType> orderedNodes;
11317 for (int idom = 0; idom <orderDom.size(); idom++)
11318 orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
11319 SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11321 stringstream grpname;
11323 grpname << 0 << "_" << 0;
11325 string namegrp = grpname.str();
11326 if (!mapOfJunctionGroups.count(namegrp))
11327 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
11328 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11330 sgrp->Add(face->GetID());
11333 // --- iterate on edgesMultiDomains
11335 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11336 for (; ite != edgesMultiDomains.end(); ++ite)
11338 vector<int> nodes = ite->first;
11339 vector<int> orderDom = ite->second;
11340 vector<vtkIdType> orderedNodes;
11341 if (nodes.size() == 2)
11343 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11344 for (int ino=0; ino < nodes.size(); ino++)
11345 if (orderDom.size() == 3)
11346 for (int idom = 0; idom <orderDom.size(); idom++)
11347 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11349 for (int idom = orderDom.size()-1; idom >=0; idom--)
11350 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11351 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11353 stringstream grpname;
11355 grpname << 0 << "_" << 0;
11357 string namegrp = grpname.str();
11358 if (!mapOfJunctionGroups.count(namegrp))
11359 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11360 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11362 sgrp->Add(vol->GetID());
11366 MESSAGE("Quadratic multiple joints not implemented");
11367 // TODO quadratic nodes
11372 // --- list the explicit faces and edges of the mesh that need to be modified,
11373 // i.e. faces and edges built with one or more duplicated nodes.
11374 // associate these faces or edges to their corresponding domain.
11375 // only the first domain found is kept when a face or edge is shared
11377 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11378 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11379 faceOrEdgeDom.clear();
11382 for (int idomain = 0; idomain < theElems.size(); idomain++)
11384 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11385 for (; itnod != nodeDomains.end(); ++itnod)
11387 int oldId = itnod->first;
11388 //MESSAGE(" node " << oldId);
11389 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11390 for (int i = 0; i < l.ncells; i++)
11392 int vtkId = l.cells[i];
11393 int vtkType = grid->GetCellType(vtkId);
11394 int downId = grid->CellIdToDownId(vtkId);
11396 continue; // new cells: not to be modified
11397 DownIdType aCell(downId, vtkType);
11398 int volParents[1000];
11399 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11400 for (int j = 0; j < nbvol; j++)
11401 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11402 if (!feDom.count(vtkId))
11404 feDom[vtkId] = idomain;
11405 faceOrEdgeDom[aCell] = emptyMap;
11406 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11407 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11408 // << " type " << vtkType << " downId " << downId);
11414 // --- iterate on shared faces (volumes to modify, face to extrude)
11415 // get node id's of the face
11416 // replace old nodes by new nodes in volumes, and update inverse connectivity
11418 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11419 for (int m=0; m<3; m++)
11421 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11422 itface = (*amap).begin();
11423 for (; itface != (*amap).end(); ++itface)
11425 DownIdType face = itface->first;
11426 std::set<int> oldNodes;
11427 std::set<int>::iterator itn;
11429 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11430 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11431 std::map<int, int> localClonedNodeIds;
11433 std::map<int, int> domvol = itface->second;
11434 std::map<int, int>::iterator itdom = domvol.begin();
11435 for (; itdom != domvol.end(); ++itdom)
11437 int idom = itdom->first;
11438 int vtkVolId = itdom->second;
11439 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11440 localClonedNodeIds.clear();
11441 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11444 if (nodeDomains[oldId].count(idom))
11446 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11447 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11450 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11455 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11456 grid->BuildLinks();
11464 * \brief Double nodes on some external faces and create flat elements.
11465 * Flat elements are mainly used by some types of mechanic calculations.
11467 * Each group of the list must be constituted of faces.
11468 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11469 * @param theElems - list of groups of faces, where a group of faces is a set of
11470 * SMDS_MeshElements sorted by Id.
11471 * @return TRUE if operation has been completed successfully, FALSE otherwise
11473 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11475 MESSAGE("-------------------------------------------------");
11476 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11477 MESSAGE("-------------------------------------------------");
11479 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11481 // --- For each group of faces
11482 // duplicate the nodes, create a flat element based on the face
11483 // replace the nodes of the faces by their clones
11485 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11486 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11487 clonedNodes.clear();
11488 intermediateNodes.clear();
11489 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11490 mapOfJunctionGroups.clear();
11492 for (int idom = 0; idom < theElems.size(); idom++)
11494 const TIDSortedElemSet& domain = theElems[idom];
11495 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11496 for (; elemItr != domain.end(); ++elemItr)
11498 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11499 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11502 // MESSAGE("aFace=" << aFace->GetID());
11503 bool isQuad = aFace->IsQuadratic();
11504 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11506 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11508 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11509 while (nodeIt->more())
11511 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11512 bool isMedium = isQuad && (aFace->IsMediumNode(node));
11514 ln2.push_back(node);
11516 ln0.push_back(node);
11518 const SMDS_MeshNode* clone = 0;
11519 if (!clonedNodes.count(node))
11521 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11522 clonedNodes[node] = clone;
11525 clone = clonedNodes[node];
11528 ln3.push_back(clone);
11530 ln1.push_back(clone);
11532 const SMDS_MeshNode* inter = 0;
11533 if (isQuad && (!isMedium))
11535 if (!intermediateNodes.count(node))
11537 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11538 intermediateNodes[node] = inter;
11541 inter = intermediateNodes[node];
11542 ln4.push_back(inter);
11546 // --- extrude the face
11548 vector<const SMDS_MeshNode*> ln;
11549 SMDS_MeshVolume* vol = 0;
11550 vtkIdType aType = aFace->GetVtkType();
11554 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11555 // MESSAGE("vol prism " << vol->GetID());
11556 ln.push_back(ln1[0]);
11557 ln.push_back(ln1[1]);
11558 ln.push_back(ln1[2]);
11561 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11562 // MESSAGE("vol hexa " << vol->GetID());
11563 ln.push_back(ln1[0]);
11564 ln.push_back(ln1[1]);
11565 ln.push_back(ln1[2]);
11566 ln.push_back(ln1[3]);
11568 case VTK_QUADRATIC_TRIANGLE:
11569 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11570 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11571 // MESSAGE("vol quad prism " << vol->GetID());
11572 ln.push_back(ln1[0]);
11573 ln.push_back(ln1[1]);
11574 ln.push_back(ln1[2]);
11575 ln.push_back(ln3[0]);
11576 ln.push_back(ln3[1]);
11577 ln.push_back(ln3[2]);
11579 case VTK_QUADRATIC_QUAD:
11580 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11581 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11582 // ln4[0], ln4[1], ln4[2], ln4[3]);
11583 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11584 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11585 ln4[0], ln4[1], ln4[2], ln4[3]);
11586 // MESSAGE("vol quad hexa " << vol->GetID());
11587 ln.push_back(ln1[0]);
11588 ln.push_back(ln1[1]);
11589 ln.push_back(ln1[2]);
11590 ln.push_back(ln1[3]);
11591 ln.push_back(ln3[0]);
11592 ln.push_back(ln3[1]);
11593 ln.push_back(ln3[2]);
11594 ln.push_back(ln3[3]);
11604 stringstream grpname;
11608 string namegrp = grpname.str();
11609 if (!mapOfJunctionGroups.count(namegrp))
11610 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11611 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11613 sgrp->Add(vol->GetID());
11616 // --- modify the face
11618 aFace->ChangeNodes(&ln[0], ln.size());
11624 //================================================================================
11626 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11627 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11628 * \return TRUE if operation has been completed successfully, FALSE otherwise
11630 //================================================================================
11632 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11634 // iterates on volume elements and detect all free faces on them
11635 SMESHDS_Mesh* aMesh = GetMeshDS();
11638 //bool res = false;
11639 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11640 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11643 const SMDS_MeshVolume* volume = vIt->next();
11644 SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11645 vTool.SetExternalNormal();
11646 //const bool isPoly = volume->IsPoly();
11647 const int iQuad = volume->IsQuadratic();
11648 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11650 if (!vTool.IsFreeFace(iface))
11653 vector<const SMDS_MeshNode *> nodes;
11654 int nbFaceNodes = vTool.NbFaceNodes(iface);
11655 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11657 for ( ; inode < nbFaceNodes; inode += iQuad+1)
11658 nodes.push_back(faceNodes[inode]);
11659 if (iQuad) { // add medium nodes
11660 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11661 nodes.push_back(faceNodes[inode]);
11662 if ( nbFaceNodes == 9 ) // bi-quadratic quad
11663 nodes.push_back(faceNodes[8]);
11665 // add new face based on volume nodes
11666 if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11668 continue; // face already exsist
11670 AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11674 return ( nbFree==(nbExisted+nbCreated) );
11679 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11681 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11683 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11686 //================================================================================
11688 * \brief Creates missing boundary elements
11689 * \param elements - elements whose boundary is to be checked
11690 * \param dimension - defines type of boundary elements to create
11691 * \param group - a group to store created boundary elements in
11692 * \param targetMesh - a mesh to store created boundary elements in
11693 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11694 * \param toCopyExistingBoundary - if true, not only new but also pre-existing
11695 * boundary elements will be copied into the targetMesh
11696 * \param toAddExistingBondary - if true, not only new but also pre-existing
11697 * boundary elements will be added into the new group
11698 * \param aroundElements - if true, elements will be created on boundary of given
11699 * elements else, on boundary of the whole mesh.
11700 * \return nb of added boundary elements
11702 //================================================================================
11704 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11705 Bnd_Dimension dimension,
11706 SMESH_Group* group/*=0*/,
11707 SMESH_Mesh* targetMesh/*=0*/,
11708 bool toCopyElements/*=false*/,
11709 bool toCopyExistingBoundary/*=false*/,
11710 bool toAddExistingBondary/*= false*/,
11711 bool aroundElements/*= false*/)
11713 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11714 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11715 // hope that all elements are of the same type, do not check them all
11716 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11717 throw SALOME_Exception(LOCALIZED("wrong element type"));
11720 toCopyElements = toCopyExistingBoundary = false;
11722 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11723 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11724 int nbAddedBnd = 0;
11726 // editor adding present bnd elements and optionally holding elements to add to the group
11727 SMESH_MeshEditor* presentEditor;
11728 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11729 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11731 SMESH_MesherHelper helper( *myMesh );
11732 const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11733 SMDS_VolumeTool vTool;
11734 TIDSortedElemSet avoidSet;
11735 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11738 typedef vector<const SMDS_MeshNode*> TConnectivity;
11740 SMDS_ElemIteratorPtr eIt;
11741 if (elements.empty())
11742 eIt = aMesh->elementsIterator(elemType);
11744 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11746 while (eIt->more())
11748 const SMDS_MeshElement* elem = eIt->next();
11749 const int iQuad = elem->IsQuadratic();
11751 // ------------------------------------------------------------------------------------
11752 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11753 // ------------------------------------------------------------------------------------
11754 vector<const SMDS_MeshElement*> presentBndElems;
11755 vector<TConnectivity> missingBndElems;
11756 TConnectivity nodes;
11757 if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11759 vTool.SetExternalNormal();
11760 const SMDS_MeshElement* otherVol = 0;
11761 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11763 if ( !vTool.IsFreeFace(iface, &otherVol) &&
11764 ( !aroundElements || elements.count( otherVol )))
11766 const int nbFaceNodes = vTool.NbFaceNodes(iface);
11767 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11768 if ( missType == SMDSAbs_Edge ) // boundary edges
11770 nodes.resize( 2+iQuad );
11771 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11773 for ( int j = 0; j < nodes.size(); ++j )
11775 if ( const SMDS_MeshElement* edge =
11776 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11777 presentBndElems.push_back( edge );
11779 missingBndElems.push_back( nodes );
11782 else // boundary face
11785 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11786 nodes.push_back( nn[inode] );
11787 if (iQuad) // add medium nodes
11788 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11789 nodes.push_back( nn[inode] );
11790 int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11792 nodes.push_back( vTool.GetNodes()[ iCenter ] );
11794 if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11795 SMDSAbs_Face, /*noMedium=*/false ))
11796 presentBndElems.push_back( f );
11798 missingBndElems.push_back( nodes );
11800 if ( targetMesh != myMesh )
11802 // add 1D elements on face boundary to be added to a new mesh
11803 const SMDS_MeshElement* edge;
11804 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11807 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11809 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11810 if ( edge && avoidSet.insert( edge ).second )
11811 presentBndElems.push_back( edge );
11817 else // elem is a face ------------------------------------------
11819 avoidSet.clear(), avoidSet.insert( elem );
11820 int nbNodes = elem->NbCornerNodes();
11821 nodes.resize( 2 /*+ iQuad*/);
11822 for ( int i = 0; i < nbNodes; i++ )
11824 nodes[0] = elem->GetNode(i);
11825 nodes[1] = elem->GetNode((i+1)%nbNodes);
11826 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11827 continue; // not free link
11830 //nodes[2] = elem->GetNode( i + nbNodes );
11831 if ( const SMDS_MeshElement* edge =
11832 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11833 presentBndElems.push_back( edge );
11835 missingBndElems.push_back( nodes );
11839 // ---------------------------------
11840 // 2. Add missing boundary elements
11841 // ---------------------------------
11842 if ( targetMesh != myMesh )
11843 // instead of making a map of nodes in this mesh and targetMesh,
11844 // we create nodes with same IDs.
11845 for ( int i = 0; i < missingBndElems.size(); ++i )
11847 TConnectivity& srcNodes = missingBndElems[i];
11848 TConnectivity nodes( srcNodes.size() );
11849 for ( inode = 0; inode < nodes.size(); ++inode )
11850 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11851 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11853 /*noMedium=*/false))
11855 tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11859 for ( int i = 0; i < missingBndElems.size(); ++i )
11861 TConnectivity& nodes = missingBndElems[i];
11862 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11864 /*noMedium=*/false))
11866 SMDS_MeshElement* elem =
11867 tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11870 // try to set a new element to a shape
11871 if ( myMesh->HasShapeToMesh() )
11874 set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11875 const int nbN = nodes.size() / (iQuad+1 );
11876 for ( inode = 0; inode < nbN && ok; ++inode )
11878 pair<int, TopAbs_ShapeEnum> i_stype =
11879 helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11880 if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11881 mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11883 if ( ok && mediumShapes.size() > 1 )
11885 set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11886 pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11887 for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11889 if (( ok = ( stype_i->first != stype_i_0.first )))
11890 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11891 aMesh->IndexToShape( stype_i_0.second ));
11894 if ( ok && mediumShapes.begin()->first == missShapeType )
11895 aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11899 // ----------------------------------
11900 // 3. Copy present boundary elements
11901 // ----------------------------------
11902 if ( toCopyExistingBoundary )
11903 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11905 const SMDS_MeshElement* e = presentBndElems[i];
11906 TConnectivity nodes( e->NbNodes() );
11907 for ( inode = 0; inode < nodes.size(); ++inode )
11908 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11909 presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11911 else // store present elements to add them to a group
11912 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11914 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11917 } // loop on given elements
11919 // ---------------------------------------------
11920 // 4. Fill group with boundary elements
11921 // ---------------------------------------------
11924 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11925 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11926 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11928 tgtEditor.myLastCreatedElems.Clear();
11929 tgtEditor2.myLastCreatedElems.Clear();
11931 // -----------------------
11932 // 5. Copy given elements
11933 // -----------------------
11934 if ( toCopyElements && targetMesh != myMesh )
11936 if (elements.empty())
11937 eIt = aMesh->elementsIterator(elemType);
11939 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11940 while (eIt->more())
11942 const SMDS_MeshElement* elem = eIt->next();
11943 TConnectivity nodes( elem->NbNodes() );
11944 for ( inode = 0; inode < nodes.size(); ++inode )
11945 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11946 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11948 tgtEditor.myLastCreatedElems.Clear();