1 // Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File : SMESH_MeshEditor.cxx
24 // Created : Mon Apr 12 16:10:22 2004
25 // Author : Edward AGAPOV (eap)
28 #include "SMESH_MeshEditor.hxx"
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 //#include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_LinearEdge.hxx"
39 #include "SMDS_Downward.hxx"
40 #include "SMDS_SetIterator.hxx"
42 #include "SMESHDS_Group.hxx"
43 #include "SMESHDS_Mesh.hxx"
45 #include "SMESH_Algo.hxx"
46 #include "SMESH_ControlsDef.hxx"
47 #include "SMESH_Group.hxx"
48 #include "SMESH_MesherHelper.hxx"
49 #include "SMESH_OctreeNode.hxx"
50 #include "SMESH_subMesh.hxx"
52 #include <Basics_OCCTVersion.hxx>
54 #include "utilities.h"
56 #include <BRepAdaptor_Surface.hxx>
57 #include <BRepClass3d_SolidClassifier.hxx>
58 #include <BRep_Tool.hxx>
60 #include <Extrema_GenExtPS.hxx>
61 #include <Extrema_POnCurv.hxx>
62 #include <Extrema_POnSurf.hxx>
63 #include <GC_MakeSegment.hxx>
64 #include <Geom2d_Curve.hxx>
65 #include <GeomAPI_ExtremaCurveCurve.hxx>
66 #include <GeomAdaptor_Surface.hxx>
67 #include <Geom_Curve.hxx>
68 #include <Geom_Line.hxx>
69 #include <Geom_Surface.hxx>
70 #include <IntAna_IntConicQuad.hxx>
71 #include <IntAna_Quadric.hxx>
72 #include <Precision.hxx>
73 #include <TColStd_ListOfInteger.hxx>
74 #include <TopAbs_State.hxx>
76 #include <TopExp_Explorer.hxx>
77 #include <TopTools_ListIteratorOfListOfShape.hxx>
78 #include <TopTools_ListOfShape.hxx>
79 #include <TopTools_SequenceOfShape.hxx>
81 #include <TopoDS_Face.hxx>
87 #include <gp_Trsf.hxx>
101 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
104 using namespace SMESH::Controls;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
107 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
109 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
111 //=======================================================================
112 //function : SMESH_MeshEditor
114 //=======================================================================
116 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
117 :myMesh( theMesh ) // theMesh may be NULL
121 //=======================================================================
125 //=======================================================================
128 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
129 const SMDSAbs_ElementType type,
133 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
134 SMDS_MeshElement* e = 0;
135 int nbnode = node.size();
136 SMESHDS_Mesh* mesh = GetMeshDS();
141 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
142 else e = mesh->AddFace (node[0], node[1], node[2] );
144 else if (nbnode == 4) {
145 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
146 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
148 else if (nbnode == 6) {
149 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150 node[4], node[5], ID);
151 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
154 else if (nbnode == 8) {
155 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
156 node[4], node[5], node[6], node[7], ID);
157 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
158 node[4], node[5], node[6], node[7] );
161 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
162 else e = mesh->AddPolygonalFace (node );
169 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
170 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
172 else if (nbnode == 5) {
173 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
178 else if (nbnode == 6) {
179 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180 node[4], node[5], ID);
181 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
184 else if (nbnode == 8) {
185 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186 node[4], node[5], node[6], node[7], ID);
187 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
188 node[4], node[5], node[6], node[7] );
190 else if (nbnode == 10) {
191 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192 node[4], node[5], node[6], node[7],
193 node[8], node[9], ID);
194 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
195 node[4], node[5], node[6], node[7],
198 else if (nbnode == 13) {
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], node[10],node[11],
203 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
204 node[4], node[5], node[6], node[7],
205 node[8], node[9], node[10],node[11],
208 else if (nbnode == 15) {
209 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
210 node[4], node[5], node[6], node[7],
211 node[8], node[9], node[10],node[11],
212 node[12],node[13],node[14],ID);
213 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
214 node[4], node[5], node[6], node[7],
215 node[8], node[9], node[10],node[11],
216 node[12],node[13],node[14] );
218 else if (nbnode == 20) {
219 if ( ID >= 1 ) e = mesh->AddVolumeWithID(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],
222 node[12],node[13],node[14],node[15],
223 node[16],node[17],node[18],node[19],ID);
224 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
225 node[4], node[5], node[6], node[7],
226 node[8], node[9], node[10],node[11],
227 node[12],node[13],node[14],node[15],
228 node[16],node[17],node[18],node[19] );
235 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
236 else e = mesh->AddEdge (node[0], node[1] );
238 else if ( nbnode == 3 ) {
239 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
240 else e = mesh->AddEdge (node[0], node[1], node[2] );
244 case SMDSAbs_0DElement:
246 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
247 else e = mesh->Add0DElement (node[0] );
252 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
253 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
258 if ( e ) myLastCreatedElems.Append( e );
262 //=======================================================================
266 //=======================================================================
268 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
269 const SMDSAbs_ElementType type,
273 vector<const SMDS_MeshNode*> nodes;
274 nodes.reserve( nodeIDs.size() );
275 vector<int>::const_iterator id = nodeIDs.begin();
276 while ( id != nodeIDs.end() ) {
277 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
278 nodes.push_back( node );
282 return AddElement( nodes, type, isPoly, ID );
285 //=======================================================================
287 //purpose : Remove a node or an element.
288 // Modify a compute state of sub-meshes which become empty
289 //=======================================================================
291 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
294 myLastCreatedElems.Clear();
295 myLastCreatedNodes.Clear();
297 SMESHDS_Mesh* aMesh = GetMeshDS();
298 set< SMESH_subMesh *> smmap;
301 list<int>::const_iterator it = theIDs.begin();
302 for ( ; it != theIDs.end(); it++ ) {
303 const SMDS_MeshElement * elem;
305 elem = aMesh->FindNode( *it );
307 elem = aMesh->FindElement( *it );
311 // Notify VERTEX sub-meshes about modification
313 const SMDS_MeshNode* node = cast2Node( elem );
314 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
315 if ( int aShapeID = node->getshapeId() )
316 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
319 // Find sub-meshes to notify about modification
320 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
321 // while ( nodeIt->more() ) {
322 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
323 // const SMDS_PositionPtr& aPosition = node->GetPosition();
324 // if ( aPosition.get() ) {
325 // if ( int aShapeID = aPosition->GetShapeId() ) {
326 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
327 // smmap.insert( sm );
334 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
336 aMesh->RemoveElement( elem );
340 // Notify sub-meshes about modification
341 if ( !smmap.empty() ) {
342 set< SMESH_subMesh *>::iterator smIt;
343 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
344 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
347 // // Check if the whole mesh becomes empty
348 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
349 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
354 //=======================================================================
355 //function : FindShape
356 //purpose : Return an index of the shape theElem is on
357 // or zero if a shape not found
358 //=======================================================================
360 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
362 myLastCreatedElems.Clear();
363 myLastCreatedNodes.Clear();
365 SMESHDS_Mesh * aMesh = GetMeshDS();
366 if ( aMesh->ShapeToMesh().IsNull() )
369 int aShapeID = theElem->getshapeId();
373 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
374 if ( sm->Contains( theElem ))
377 if ( theElem->GetType() == SMDSAbs_Node ) {
378 MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
381 MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
384 TopoDS_Shape aShape; // the shape a node of theElem is on
385 if ( theElem->GetType() != SMDSAbs_Node )
387 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
388 while ( nodeIt->more() ) {
389 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
390 if ((aShapeID = node->getshapeId()) > 0) {
391 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
392 if ( sm->Contains( theElem ))
394 if ( aShape.IsNull() )
395 aShape = aMesh->IndexToShape( aShapeID );
401 // None of nodes is on a proper shape,
402 // find the shape among ancestors of aShape on which a node is
403 if ( !aShape.IsNull() ) {
404 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
405 for ( ; ancIt.More(); ancIt.Next() ) {
406 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
407 if ( sm && sm->Contains( theElem ))
408 return aMesh->ShapeToIndex( ancIt.Value() );
413 const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
414 map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
415 for ( ; id_sm != id2sm.end(); ++id_sm )
416 if ( id_sm->second->Contains( theElem ))
420 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
424 //=======================================================================
425 //function : IsMedium
427 //=======================================================================
429 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
430 const SMDSAbs_ElementType typeToCheck)
432 bool isMedium = false;
433 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
434 while (it->more() && !isMedium ) {
435 const SMDS_MeshElement* elem = it->next();
436 isMedium = elem->IsMediumNode(node);
441 //=======================================================================
442 //function : ShiftNodesQuadTria
444 // Shift nodes in the array corresponded to quadratic triangle
445 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
446 //=======================================================================
447 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
449 const SMDS_MeshNode* nd1 = aNodes[0];
450 aNodes[0] = aNodes[1];
451 aNodes[1] = aNodes[2];
453 const SMDS_MeshNode* nd2 = aNodes[3];
454 aNodes[3] = aNodes[4];
455 aNodes[4] = aNodes[5];
459 //=======================================================================
460 //function : GetNodesFromTwoTria
462 // Shift nodes in the array corresponded to quadratic triangle
463 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
464 //=======================================================================
465 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
466 const SMDS_MeshElement * theTria2,
467 const SMDS_MeshNode* N1[],
468 const SMDS_MeshNode* N2[])
470 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
473 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
476 if(it->more()) return false;
477 it = theTria2->nodesIterator();
480 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
483 if(it->more()) return false;
485 int sames[3] = {-1,-1,-1};
497 if(nbsames!=2) return false;
499 ShiftNodesQuadTria(N1);
501 ShiftNodesQuadTria(N1);
504 i = sames[0] + sames[1] + sames[2];
506 ShiftNodesQuadTria(N2);
508 // now we receive following N1 and N2 (using numeration as above image)
509 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
510 // i.e. first nodes from both arrays determ new diagonal
514 //=======================================================================
515 //function : InverseDiag
516 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
517 // but having other common link.
518 // Return False if args are improper
519 //=======================================================================
521 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
522 const SMDS_MeshElement * theTria2 )
524 MESSAGE("InverseDiag");
525 myLastCreatedElems.Clear();
526 myLastCreatedNodes.Clear();
528 if (!theTria1 || !theTria2)
531 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
532 if (!F1) return false;
533 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
534 if (!F2) return false;
535 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
536 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
538 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
539 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
543 // put nodes in array and find out indices of the same ones
544 const SMDS_MeshNode* aNodes [6];
545 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
547 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
548 while ( it->more() ) {
549 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
551 if ( i > 2 ) // theTria2
552 // find same node of theTria1
553 for ( int j = 0; j < 3; j++ )
554 if ( aNodes[ i ] == aNodes[ j ]) {
563 return false; // theTria1 is not a triangle
564 it = theTria2->nodesIterator();
566 if ( i == 6 && it->more() )
567 return false; // theTria2 is not a triangle
570 // find indices of 1,2 and of A,B in theTria1
571 int iA = 0, iB = 0, i1 = 0, i2 = 0;
572 for ( i = 0; i < 6; i++ ) {
573 if ( sameInd [ i ] == 0 ) {
582 // nodes 1 and 2 should not be the same
583 if ( aNodes[ i1 ] == aNodes[ i2 ] )
587 aNodes[ iA ] = aNodes[ i2 ];
589 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
591 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
592 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
596 } // end if(F1 && F2)
598 // check case of quadratic faces
599 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
601 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
605 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
606 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
614 const SMDS_MeshNode* N1 [6];
615 const SMDS_MeshNode* N2 [6];
616 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
618 // now we receive following N1 and N2 (using numeration as above image)
619 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
620 // i.e. first nodes from both arrays determ new diagonal
622 const SMDS_MeshNode* N1new [6];
623 const SMDS_MeshNode* N2new [6];
636 // replaces nodes in faces
637 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
638 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
643 //=======================================================================
644 //function : findTriangles
645 //purpose : find triangles sharing theNode1-theNode2 link
646 //=======================================================================
648 static bool findTriangles(const SMDS_MeshNode * theNode1,
649 const SMDS_MeshNode * theNode2,
650 const SMDS_MeshElement*& theTria1,
651 const SMDS_MeshElement*& theTria2)
653 if ( !theNode1 || !theNode2 ) return false;
655 theTria1 = theTria2 = 0;
657 set< const SMDS_MeshElement* > emap;
658 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
660 const SMDS_MeshElement* elem = it->next();
661 if ( elem->NbNodes() == 3 )
664 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
666 const SMDS_MeshElement* elem = it->next();
667 if ( emap.find( elem ) != emap.end() ) {
669 // theTria1 must be element with minimum ID
670 if( theTria1->GetID() < elem->GetID() ) {
684 return ( theTria1 && theTria2 );
687 //=======================================================================
688 //function : InverseDiag
689 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
690 // with ones built on the same 4 nodes but having other common link.
691 // Return false if proper faces not found
692 //=======================================================================
694 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
695 const SMDS_MeshNode * theNode2)
697 myLastCreatedElems.Clear();
698 myLastCreatedNodes.Clear();
700 MESSAGE( "::InverseDiag()" );
702 const SMDS_MeshElement *tr1, *tr2;
703 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
706 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
707 if (!F1) return false;
708 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
709 if (!F2) return false;
710 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
711 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
713 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
714 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
718 // put nodes in array
719 // and find indices of 1,2 and of A in tr1 and of B in tr2
720 int i, iA1 = 0, i1 = 0;
721 const SMDS_MeshNode* aNodes1 [3];
722 SMDS_ElemIteratorPtr it;
723 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
724 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
725 if ( aNodes1[ i ] == theNode1 )
726 iA1 = i; // node A in tr1
727 else if ( aNodes1[ i ] != theNode2 )
731 const SMDS_MeshNode* aNodes2 [3];
732 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
733 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
734 if ( aNodes2[ i ] == theNode2 )
735 iB2 = i; // node B in tr2
736 else if ( aNodes2[ i ] != theNode1 )
740 // nodes 1 and 2 should not be the same
741 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
745 aNodes1[ iA1 ] = aNodes2[ i2 ];
747 aNodes2[ iB2 ] = aNodes1[ i1 ];
749 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
750 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
755 // check case of quadratic faces
756 return InverseDiag(tr1,tr2);
759 //=======================================================================
760 //function : getQuadrangleNodes
761 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
762 // fusion of triangles tr1 and tr2 having shared link on
763 // theNode1 and theNode2
764 //=======================================================================
766 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
767 const SMDS_MeshNode * theNode1,
768 const SMDS_MeshNode * theNode2,
769 const SMDS_MeshElement * tr1,
770 const SMDS_MeshElement * tr2 )
772 if( tr1->NbNodes() != tr2->NbNodes() )
774 // find the 4-th node to insert into tr1
775 const SMDS_MeshNode* n4 = 0;
776 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
778 while ( !n4 && i<3 ) {
779 const SMDS_MeshNode * n = cast2Node( it->next() );
781 bool isDiag = ( n == theNode1 || n == theNode2 );
785 // Make an array of nodes to be in a quadrangle
786 int iNode = 0, iFirstDiag = -1;
787 it = tr1->nodesIterator();
790 const SMDS_MeshNode * n = cast2Node( it->next() );
792 bool isDiag = ( n == theNode1 || n == theNode2 );
794 if ( iFirstDiag < 0 )
796 else if ( iNode - iFirstDiag == 1 )
797 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
799 else if ( n == n4 ) {
800 return false; // tr1 and tr2 should not have all the same nodes
802 theQuadNodes[ iNode++ ] = n;
804 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
805 theQuadNodes[ iNode ] = n4;
810 //=======================================================================
811 //function : DeleteDiag
812 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
813 // with a quadrangle built on the same 4 nodes.
814 // Return false if proper faces not found
815 //=======================================================================
817 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
818 const SMDS_MeshNode * theNode2)
820 myLastCreatedElems.Clear();
821 myLastCreatedNodes.Clear();
823 MESSAGE( "::DeleteDiag()" );
825 const SMDS_MeshElement *tr1, *tr2;
826 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
829 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
830 if (!F1) return false;
831 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
832 if (!F2) return false;
833 SMESHDS_Mesh * aMesh = GetMeshDS();
835 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
836 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
838 const SMDS_MeshNode* aNodes [ 4 ];
839 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
842 const SMDS_MeshElement* newElem = 0;
843 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
844 myLastCreatedElems.Append(newElem);
845 AddToSameGroups( newElem, tr1, aMesh );
846 int aShapeId = tr1->getshapeId();
849 aMesh->SetMeshElementOnShape( newElem, aShapeId );
851 aMesh->RemoveElement( tr1 );
852 aMesh->RemoveElement( tr2 );
857 // check case of quadratic faces
858 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
860 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
864 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
865 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
873 const SMDS_MeshNode* N1 [6];
874 const SMDS_MeshNode* N2 [6];
875 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
877 // now we receive following N1 and N2 (using numeration as above image)
878 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
879 // i.e. first nodes from both arrays determ new diagonal
881 const SMDS_MeshNode* aNodes[8];
891 const SMDS_MeshElement* newElem = 0;
892 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
893 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
894 myLastCreatedElems.Append(newElem);
895 AddToSameGroups( newElem, tr1, aMesh );
896 int aShapeId = tr1->getshapeId();
899 aMesh->SetMeshElementOnShape( newElem, aShapeId );
901 aMesh->RemoveElement( tr1 );
902 aMesh->RemoveElement( tr2 );
904 // remove middle node (9)
905 GetMeshDS()->RemoveNode( N1[4] );
910 //=======================================================================
911 //function : Reorient
912 //purpose : Reverse theElement orientation
913 //=======================================================================
915 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
918 myLastCreatedElems.Clear();
919 myLastCreatedNodes.Clear();
923 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
924 if ( !it || !it->more() )
927 switch ( theElem->GetType() ) {
931 if(!theElem->IsQuadratic()) {
932 int i = theElem->NbNodes();
933 vector<const SMDS_MeshNode*> aNodes( i );
935 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
936 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
939 // quadratic elements
940 if(theElem->GetType()==SMDSAbs_Edge) {
941 vector<const SMDS_MeshNode*> aNodes(3);
942 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
943 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
944 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
945 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
948 int nbn = theElem->NbNodes();
949 vector<const SMDS_MeshNode*> aNodes(nbn);
950 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
952 for(; i<nbn/2; i++) {
953 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
955 for(i=0; i<nbn/2; i++) {
956 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
958 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
962 case SMDSAbs_Volume: {
963 if (theElem->IsPoly()) {
964 // TODO reorient vtk polyhedron
965 MESSAGE("reorient vtk polyhedron ?");
966 const SMDS_VtkVolume* aPolyedre =
967 dynamic_cast<const SMDS_VtkVolume*>( theElem );
969 MESSAGE("Warning: bad volumic element");
973 int nbFaces = aPolyedre->NbFaces();
974 vector<const SMDS_MeshNode *> poly_nodes;
975 vector<int> quantities (nbFaces);
977 // reverse each face of the polyedre
978 for (int iface = 1; iface <= nbFaces; iface++) {
979 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
980 quantities[iface - 1] = nbFaceNodes;
982 for (inode = nbFaceNodes; inode >= 1; inode--) {
983 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
984 poly_nodes.push_back(curNode);
988 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
992 SMDS_VolumeTool vTool;
993 if ( !vTool.Set( theElem ))
996 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
997 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1006 //=======================================================================
1007 //function : getBadRate
1009 //=======================================================================
1011 static double getBadRate (const SMDS_MeshElement* theElem,
1012 SMESH::Controls::NumericalFunctorPtr& theCrit)
1014 SMESH::Controls::TSequenceOfXYZ P;
1015 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1017 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1018 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1021 //=======================================================================
1022 //function : QuadToTri
1023 //purpose : Cut quadrangles into triangles.
1024 // theCrit is used to select a diagonal to cut
1025 //=======================================================================
1027 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1028 SMESH::Controls::NumericalFunctorPtr theCrit)
1030 myLastCreatedElems.Clear();
1031 myLastCreatedNodes.Clear();
1033 MESSAGE( "::QuadToTri()" );
1035 if ( !theCrit.get() )
1038 SMESHDS_Mesh * aMesh = GetMeshDS();
1040 Handle(Geom_Surface) surface;
1041 SMESH_MesherHelper helper( *GetMesh() );
1043 TIDSortedElemSet::iterator itElem;
1044 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1045 const SMDS_MeshElement* elem = *itElem;
1046 if ( !elem || elem->GetType() != SMDSAbs_Face )
1048 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1051 // retrieve element nodes
1052 const SMDS_MeshNode* aNodes [8];
1053 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1055 while ( itN->more() )
1056 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1058 // compare two sets of possible triangles
1059 double aBadRate1, aBadRate2; // to what extent a set is bad
1060 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1061 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1062 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1064 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1065 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1066 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1068 int aShapeId = FindShape( elem );
1069 const SMDS_MeshElement* newElem1 = 0;
1070 const SMDS_MeshElement* newElem2 = 0;
1072 if( !elem->IsQuadratic() ) {
1074 // split liner quadrangle
1075 if ( aBadRate1 <= aBadRate2 ) {
1076 // tr1 + tr2 is better
1077 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1078 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1081 // tr3 + tr4 is better
1082 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1083 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1088 // split quadratic quadrangle
1090 // get surface elem is on
1091 if ( aShapeId != helper.GetSubShapeID() ) {
1095 shape = aMesh->IndexToShape( aShapeId );
1096 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1097 TopoDS_Face face = TopoDS::Face( shape );
1098 surface = BRep_Tool::Surface( face );
1099 if ( !surface.IsNull() )
1100 helper.SetSubShape( shape );
1104 const SMDS_MeshNode* aNodes [8];
1105 const SMDS_MeshNode* inFaceNode = 0;
1106 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1108 while ( itN->more() ) {
1109 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1110 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1111 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1113 inFaceNode = aNodes[ i-1 ];
1116 // find middle point for (0,1,2,3)
1117 // and create a node in this point;
1119 if ( surface.IsNull() ) {
1121 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1125 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1128 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1130 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1132 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1133 myLastCreatedNodes.Append(newN);
1135 // create a new element
1136 if ( aBadRate1 <= aBadRate2 ) {
1137 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1138 aNodes[6], aNodes[7], newN );
1139 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1140 newN, aNodes[4], aNodes[5] );
1143 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1144 aNodes[7], aNodes[4], newN );
1145 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1146 newN, aNodes[5], aNodes[6] );
1150 // care of a new element
1152 myLastCreatedElems.Append(newElem1);
1153 myLastCreatedElems.Append(newElem2);
1154 AddToSameGroups( newElem1, elem, aMesh );
1155 AddToSameGroups( newElem2, elem, aMesh );
1157 // put a new triangle on the same shape
1160 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1161 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1163 aMesh->RemoveElement( elem );
1168 //=======================================================================
1169 //function : BestSplit
1170 //purpose : Find better diagonal for cutting.
1171 //=======================================================================
1173 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1174 SMESH::Controls::NumericalFunctorPtr theCrit)
1176 myLastCreatedElems.Clear();
1177 myLastCreatedNodes.Clear();
1182 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1185 if( theQuad->NbNodes()==4 ||
1186 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1188 // retrieve element nodes
1189 const SMDS_MeshNode* aNodes [4];
1190 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1192 //while (itN->more())
1194 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
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 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1207 return 1; // diagonal 1-3
1209 return 2; // diagonal 2-4
1216 // Methods of splitting volumes into tetra
1218 const int theHexTo5_1[5*4+1] =
1220 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1222 const int theHexTo5_2[5*4+1] =
1224 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1226 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1228 const int theHexTo6_1[6*4+1] =
1230 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
1232 const int theHexTo6_2[6*4+1] =
1234 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
1236 const int theHexTo6_3[6*4+1] =
1238 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
1240 const int theHexTo6_4[6*4+1] =
1242 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
1244 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1246 const int thePyraTo2_1[2*4+1] =
1248 0, 1, 2, 4, 0, 2, 3, 4, -1
1250 const int thePyraTo2_2[2*4+1] =
1252 1, 2, 3, 4, 1, 3, 0, 4, -1
1254 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1256 const int thePentaTo3_1[3*4+1] =
1258 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1260 const int thePentaTo3_2[3*4+1] =
1262 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1264 const int thePentaTo3_3[3*4+1] =
1266 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1268 const int thePentaTo3_4[3*4+1] =
1270 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1272 const int thePentaTo3_5[3*4+1] =
1274 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1276 const int thePentaTo3_6[3*4+1] =
1278 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1280 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1281 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1283 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1286 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1287 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1288 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1293 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1294 bool _baryNode; //!< additional node is to be created at cell barycenter
1295 bool _ownConn; //!< to delete _connectivity in destructor
1296 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1298 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1299 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1300 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1301 bool hasFacet( const TTriangleFacet& facet ) const
1303 const int* tetConn = _connectivity;
1304 for ( ; tetConn[0] >= 0; tetConn += 4 )
1305 if (( facet.contains( tetConn[0] ) +
1306 facet.contains( tetConn[1] ) +
1307 facet.contains( tetConn[2] ) +
1308 facet.contains( tetConn[3] )) == 3 )
1314 //=======================================================================
1316 * \brief return TSplitMethod for the given element
1318 //=======================================================================
1320 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1322 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1324 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1325 // an edge and a face barycenter; tertaherdons are based on triangles and
1326 // a volume barycenter
1327 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1329 // Find out how adjacent volumes are split
1331 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1332 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1333 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1335 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1336 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1337 if ( nbNodes < 4 ) continue;
1339 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1340 const int* nInd = vol.GetFaceNodesIndices( iF );
1343 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1344 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1345 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1346 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1350 int iCom = 0; // common node of triangle faces to split into
1351 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1353 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1354 nInd[ iQ * ( (iCom+1)%nbNodes )],
1355 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1356 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1357 nInd[ iQ * ( (iCom+2)%nbNodes )],
1358 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1359 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1361 triaSplits.push_back( t012 );
1362 triaSplits.push_back( t023 );
1367 if ( !triaSplits.empty() )
1368 hasAdjacentSplits = true;
1371 // Among variants of split method select one compliant with adjacent volumes
1373 TSplitMethod method;
1374 if ( !vol.Element()->IsPoly() && !is24TetMode )
1376 int nbVariants = 2, nbTet = 0;
1377 const int** connVariants = 0;
1378 switch ( vol.Element()->GetEntityType() )
1380 case SMDSEntity_Hexa:
1381 case SMDSEntity_Quad_Hexa:
1382 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1383 connVariants = theHexTo5, nbTet = 5;
1385 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1387 case SMDSEntity_Pyramid:
1388 case SMDSEntity_Quad_Pyramid:
1389 connVariants = thePyraTo2; nbTet = 2;
1391 case SMDSEntity_Penta:
1392 case SMDSEntity_Quad_Penta:
1393 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1398 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1400 // check method compliancy with adjacent tetras,
1401 // all found splits must be among facets of tetras described by this method
1402 method = TSplitMethod( nbTet, connVariants[variant] );
1403 if ( hasAdjacentSplits && method._nbTetra > 0 )
1405 bool facetCreated = true;
1406 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1408 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1409 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1410 facetCreated = method.hasFacet( *facet );
1412 if ( !facetCreated )
1413 method = TSplitMethod(0); // incompatible method
1417 if ( method._nbTetra < 1 )
1419 // No standard method is applicable, use a generic solution:
1420 // each facet of a volume is split into triangles and
1421 // each of triangles and a volume barycenter form a tetrahedron.
1423 int* connectivity = new int[ maxTetConnSize + 1 ];
1424 method._connectivity = connectivity;
1425 method._ownConn = true;
1426 method._baryNode = true;
1429 int baryCenInd = vol.NbNodes();
1430 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1432 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1433 const int* nInd = vol.GetFaceNodesIndices( iF );
1434 // find common node of triangle facets of tetra to create
1435 int iCommon = 0; // index in linear numeration
1436 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1437 if ( !triaSplits.empty() )
1440 const TTriangleFacet* facet = &triaSplits.front();
1441 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1442 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1443 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1446 else if ( nbNodes > 3 && !is24TetMode )
1448 // find the best method of splitting into triangles by aspect ratio
1449 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1450 map< double, int > badness2iCommon;
1451 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1452 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1453 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1454 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1456 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1457 nodes[ iQ*((iLast-1)%nbNodes)],
1458 nodes[ iQ*((iLast )%nbNodes)]);
1459 double badness = getBadRate( &tria, aspectRatio );
1460 badness2iCommon.insert( make_pair( badness, iCommon ));
1462 // use iCommon with lowest badness
1463 iCommon = badness2iCommon.begin()->second;
1465 if ( iCommon >= nbNodes )
1466 iCommon = 0; // something wrong
1468 // fill connectivity of tetrahedra based on a current face
1469 int nbTet = nbNodes - 2;
1470 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1472 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1473 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1475 for ( int i = 0; i < nbTet; ++i )
1477 int i1 = i, i2 = (i+1) % nbNodes;
1478 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1479 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1480 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1481 connectivity[ connSize++ ] = faceBaryCenInd;
1482 connectivity[ connSize++ ] = baryCenInd;
1487 for ( int i = 0; i < nbTet; ++i )
1489 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1490 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1492 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1493 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1494 connectivity[ connSize++ ] = baryCenInd;
1497 method._nbTetra += nbTet;
1499 connectivity[ connSize++ ] = -1;
1503 //================================================================================
1505 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1507 //================================================================================
1509 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1511 // find the tetrahedron including the three nodes of facet
1512 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1513 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1514 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1515 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1516 while ( volIt1->more() )
1518 const SMDS_MeshElement* v = volIt1->next();
1519 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1521 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1522 while ( volIt2->more() )
1523 if ( v != volIt2->next() )
1525 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1526 while ( volIt3->more() )
1527 if ( v == volIt3->next() )
1533 //=======================================================================
1535 * \brief A key of a face of volume
1537 //=======================================================================
1539 struct TVolumeFaceKey: pair< int, pair< int, int> >
1541 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1543 TIDSortedNodeSet sortedNodes;
1544 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1545 int nbNodes = vol.NbFaceNodes( iF );
1546 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1547 for ( int i = 0; i < nbNodes; i += iQ )
1548 sortedNodes.insert( fNodes[i] );
1549 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1550 first = (*(n++))->GetID();
1551 second.first = (*(n++))->GetID();
1552 second.second = (*(n++))->GetID();
1557 //=======================================================================
1558 //function : SplitVolumesIntoTetra
1559 //purpose : Split volumic elements into tetrahedra.
1560 //=======================================================================
1562 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1563 const int theMethodFlags)
1565 // std-like iterator on coordinates of nodes of mesh element
1566 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1567 NXyzIterator xyzEnd;
1569 SMDS_VolumeTool volTool;
1570 SMESH_MesherHelper helper( *GetMesh());
1572 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1573 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1575 SMESH_SequenceOfElemPtr newNodes, newElems;
1577 // map face of volume to it's baricenrtic node
1578 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1581 TIDSortedElemSet::const_iterator elem = theElems.begin();
1582 for ( ; elem != theElems.end(); ++elem )
1584 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1585 if ( geomType <= SMDSEntity_Quad_Tetra )
1586 continue; // tetra or face or ...
1588 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1590 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1591 if ( splitMethod._nbTetra < 1 ) continue;
1593 // find submesh to add new tetras to
1594 if ( !subMesh || !subMesh->Contains( *elem ))
1596 int shapeID = FindShape( *elem );
1597 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1598 subMesh = GetMeshDS()->MeshElements( shapeID );
1601 if ( (*elem)->IsQuadratic() )
1604 // add quadratic links to the helper
1605 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1607 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1608 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1609 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1611 helper.SetIsQuadratic( true );
1616 helper.SetIsQuadratic( false );
1618 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1619 helper.SetElementsOnShape( true );
1620 if ( splitMethod._baryNode )
1622 // make a node at barycenter
1623 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1624 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1625 nodes.push_back( gcNode );
1626 newNodes.Append( gcNode );
1628 if ( !splitMethod._faceBaryNode.empty() )
1630 // make or find baricentric nodes of faces
1631 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1632 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1634 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1635 volFace2BaryNode.insert
1636 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1639 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1640 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1642 nodes.push_back( iF_n->second = f_n->second );
1647 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1648 const int* tetConn = splitMethod._connectivity;
1649 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1650 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1651 nodes[ tetConn[1] ],
1652 nodes[ tetConn[2] ],
1653 nodes[ tetConn[3] ]));
1655 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1657 // Split faces on sides of the split volume
1659 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1660 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1662 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1663 if ( nbNodes < 4 ) continue;
1665 // find an existing face
1666 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1667 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1668 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1671 helper.SetElementsOnShape( false );
1672 vector< const SMDS_MeshElement* > triangles;
1674 // find submesh to add new triangles in
1675 if ( !fSubMesh || !fSubMesh->Contains( face ))
1677 int shapeID = FindShape( face );
1678 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1680 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1681 if ( iF_n != splitMethod._faceBaryNode.end() )
1683 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1685 const SMDS_MeshNode* n1 = fNodes[iN];
1686 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1687 const SMDS_MeshNode *n3 = iF_n->second;
1688 if ( !volTool.IsFaceExternal( iF ))
1690 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1692 if ( fSubMesh && n3->getshapeId() < 1 )
1693 fSubMesh->AddNode( n3 );
1698 // among possible triangles create ones discribed by split method
1699 const int* nInd = volTool.GetFaceNodesIndices( iF );
1700 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1701 int iCom = 0; // common node of triangle faces to split into
1702 list< TTriangleFacet > facets;
1703 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1705 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1706 nInd[ iQ * ( (iCom+1)%nbNodes )],
1707 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1708 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1709 nInd[ iQ * ( (iCom+2)%nbNodes )],
1710 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1711 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1713 facets.push_back( t012 );
1714 facets.push_back( t023 );
1715 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1716 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1717 nInd[ iQ * ((iLast-1)%nbNodes )],
1718 nInd[ iQ * ((iLast )%nbNodes )]));
1722 list< TTriangleFacet >::iterator facet = facets.begin();
1723 for ( ; facet != facets.end(); ++facet )
1725 if ( !volTool.IsFaceExternal( iF ))
1726 swap( facet->_n2, facet->_n3 );
1727 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1728 volNodes[ facet->_n2 ],
1729 volNodes[ facet->_n3 ]));
1732 for ( int i = 0; i < triangles.size(); ++i )
1734 if ( !triangles[i] ) continue;
1736 fSubMesh->AddElement( triangles[i]);
1737 newElems.Append( triangles[i] );
1739 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1740 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1743 } // loop on volume faces to split them into triangles
1745 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1747 } // loop on volumes to split
1749 myLastCreatedNodes = newNodes;
1750 myLastCreatedElems = newElems;
1753 //=======================================================================
1754 //function : AddToSameGroups
1755 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1756 //=======================================================================
1758 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1759 const SMDS_MeshElement* elemInGroups,
1760 SMESHDS_Mesh * aMesh)
1762 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1763 if (!groups.empty()) {
1764 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1765 for ( ; grIt != groups.end(); grIt++ ) {
1766 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1767 if ( group && group->Contains( elemInGroups ))
1768 group->SMDSGroup().Add( elemToAdd );
1774 //=======================================================================
1775 //function : RemoveElemFromGroups
1776 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1777 //=======================================================================
1778 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1779 SMESHDS_Mesh * aMesh)
1781 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1782 if (!groups.empty())
1784 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1785 for (; GrIt != groups.end(); GrIt++)
1787 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1788 if (!grp || grp->IsEmpty()) continue;
1789 grp->SMDSGroup().Remove(removeelem);
1794 //================================================================================
1796 * \brief Replace elemToRm by elemToAdd in the all groups
1798 //================================================================================
1800 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1801 const SMDS_MeshElement* elemToAdd,
1802 SMESHDS_Mesh * aMesh)
1804 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1805 if (!groups.empty()) {
1806 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1807 for ( ; grIt != groups.end(); grIt++ ) {
1808 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1809 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1810 group->SMDSGroup().Add( elemToAdd );
1815 //================================================================================
1817 * \brief Replace elemToRm by elemToAdd in the all groups
1819 //================================================================================
1821 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1822 const vector<const SMDS_MeshElement*>& elemToAdd,
1823 SMESHDS_Mesh * aMesh)
1825 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1826 if (!groups.empty())
1828 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1829 for ( ; grIt != groups.end(); grIt++ ) {
1830 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1831 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1832 for ( int i = 0; i < elemToAdd.size(); ++i )
1833 group->SMDSGroup().Add( elemToAdd[ i ] );
1838 //=======================================================================
1839 //function : QuadToTri
1840 //purpose : Cut quadrangles into triangles.
1841 // theCrit is used to select a diagonal to cut
1842 //=======================================================================
1844 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1845 const bool the13Diag)
1847 myLastCreatedElems.Clear();
1848 myLastCreatedNodes.Clear();
1850 MESSAGE( "::QuadToTri()" );
1852 SMESHDS_Mesh * aMesh = GetMeshDS();
1854 Handle(Geom_Surface) surface;
1855 SMESH_MesherHelper helper( *GetMesh() );
1857 TIDSortedElemSet::iterator itElem;
1858 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1859 const SMDS_MeshElement* elem = *itElem;
1860 if ( !elem || elem->GetType() != SMDSAbs_Face )
1862 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1863 if(!isquad) continue;
1865 if(elem->NbNodes()==4) {
1866 // retrieve element nodes
1867 const SMDS_MeshNode* aNodes [4];
1868 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1870 while ( itN->more() )
1871 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1873 int aShapeId = FindShape( elem );
1874 const SMDS_MeshElement* newElem1 = 0;
1875 const SMDS_MeshElement* newElem2 = 0;
1877 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1878 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1881 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1882 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1884 myLastCreatedElems.Append(newElem1);
1885 myLastCreatedElems.Append(newElem2);
1886 // put a new triangle on the same shape and add to the same groups
1889 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1890 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1892 AddToSameGroups( newElem1, elem, aMesh );
1893 AddToSameGroups( newElem2, elem, aMesh );
1894 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1895 aMesh->RemoveElement( elem );
1898 // Quadratic quadrangle
1900 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1902 // get surface elem is on
1903 int aShapeId = FindShape( elem );
1904 if ( aShapeId != helper.GetSubShapeID() ) {
1908 shape = aMesh->IndexToShape( aShapeId );
1909 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1910 TopoDS_Face face = TopoDS::Face( shape );
1911 surface = BRep_Tool::Surface( face );
1912 if ( !surface.IsNull() )
1913 helper.SetSubShape( shape );
1917 const SMDS_MeshNode* aNodes [8];
1918 const SMDS_MeshNode* inFaceNode = 0;
1919 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1921 while ( itN->more() ) {
1922 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1923 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1924 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1926 inFaceNode = aNodes[ i-1 ];
1930 // find middle point for (0,1,2,3)
1931 // and create a node in this point;
1933 if ( surface.IsNull() ) {
1935 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1939 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1942 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1944 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1946 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1947 myLastCreatedNodes.Append(newN);
1949 // create a new element
1950 const SMDS_MeshElement* newElem1 = 0;
1951 const SMDS_MeshElement* newElem2 = 0;
1953 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1954 aNodes[6], aNodes[7], newN );
1955 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1956 newN, aNodes[4], aNodes[5] );
1959 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1960 aNodes[7], aNodes[4], newN );
1961 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1962 newN, aNodes[5], aNodes[6] );
1964 myLastCreatedElems.Append(newElem1);
1965 myLastCreatedElems.Append(newElem2);
1966 // put a new triangle on the same shape and add to the same groups
1969 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1970 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1972 AddToSameGroups( newElem1, elem, aMesh );
1973 AddToSameGroups( newElem2, elem, aMesh );
1974 aMesh->RemoveElement( elem );
1981 //=======================================================================
1982 //function : getAngle
1984 //=======================================================================
1986 double getAngle(const SMDS_MeshElement * tr1,
1987 const SMDS_MeshElement * tr2,
1988 const SMDS_MeshNode * n1,
1989 const SMDS_MeshNode * n2)
1991 double angle = 2*PI; // bad angle
1994 SMESH::Controls::TSequenceOfXYZ P1, P2;
1995 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1996 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1999 if(!tr1->IsQuadratic())
2000 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2002 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2003 if ( N1.SquareMagnitude() <= gp::Resolution() )
2005 if(!tr2->IsQuadratic())
2006 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2008 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2009 if ( N2.SquareMagnitude() <= gp::Resolution() )
2012 // find the first diagonal node n1 in the triangles:
2013 // take in account a diagonal link orientation
2014 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2015 for ( int t = 0; t < 2; t++ ) {
2016 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2017 int i = 0, iDiag = -1;
2018 while ( it->more()) {
2019 const SMDS_MeshElement *n = it->next();
2020 if ( n == n1 || n == n2 ) {
2024 if ( i - iDiag == 1 )
2025 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2034 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2037 angle = N1.Angle( N2 );
2042 // =================================================
2043 // class generating a unique ID for a pair of nodes
2044 // and able to return nodes by that ID
2045 // =================================================
2049 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2050 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2053 long GetLinkID (const SMDS_MeshNode * n1,
2054 const SMDS_MeshNode * n2) const
2056 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2059 bool GetNodes (const long theLinkID,
2060 const SMDS_MeshNode* & theNode1,
2061 const SMDS_MeshNode* & theNode2) const
2063 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2064 if ( !theNode1 ) return false;
2065 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2066 if ( !theNode2 ) return false;
2072 const SMESHDS_Mesh* myMesh;
2077 //=======================================================================
2078 //function : TriToQuad
2079 //purpose : Fuse neighbour triangles into quadrangles.
2080 // theCrit is used to select a neighbour to fuse with.
2081 // theMaxAngle is a max angle between element normals at which
2082 // fusion is still performed.
2083 //=======================================================================
2085 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2086 SMESH::Controls::NumericalFunctorPtr theCrit,
2087 const double theMaxAngle)
2089 myLastCreatedElems.Clear();
2090 myLastCreatedNodes.Clear();
2092 MESSAGE( "::TriToQuad()" );
2094 if ( !theCrit.get() )
2097 SMESHDS_Mesh * aMesh = GetMeshDS();
2099 // Prepare data for algo: build
2100 // 1. map of elements with their linkIDs
2101 // 2. map of linkIDs with their elements
2103 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2104 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2105 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2106 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2108 TIDSortedElemSet::iterator itElem;
2109 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2110 const SMDS_MeshElement* elem = *itElem;
2111 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2112 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2113 if(!IsTria) continue;
2115 // retrieve element nodes
2116 const SMDS_MeshNode* aNodes [4];
2117 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2120 aNodes[ i++ ] = cast2Node( itN->next() );
2121 aNodes[ 3 ] = aNodes[ 0 ];
2124 for ( i = 0; i < 3; i++ ) {
2125 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2126 // check if elements sharing a link can be fused
2127 itLE = mapLi_listEl.find( link );
2128 if ( itLE != mapLi_listEl.end() ) {
2129 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2131 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2132 //if ( FindShape( elem ) != FindShape( elem2 ))
2133 // continue; // do not fuse triangles laying on different shapes
2134 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2135 continue; // avoid making badly shaped quads
2136 (*itLE).second.push_back( elem );
2139 mapLi_listEl[ link ].push_back( elem );
2141 mapEl_setLi [ elem ].insert( link );
2144 // Clean the maps from the links shared by a sole element, ie
2145 // links to which only one element is bound in mapLi_listEl
2147 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2148 int nbElems = (*itLE).second.size();
2149 if ( nbElems < 2 ) {
2150 const SMDS_MeshElement* elem = (*itLE).second.front();
2151 SMESH_TLink link = (*itLE).first;
2152 mapEl_setLi[ elem ].erase( link );
2153 if ( mapEl_setLi[ elem ].empty() )
2154 mapEl_setLi.erase( elem );
2158 // Algo: fuse triangles into quadrangles
2160 while ( ! mapEl_setLi.empty() ) {
2161 // Look for the start element:
2162 // the element having the least nb of shared links
2163 const SMDS_MeshElement* startElem = 0;
2165 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2166 int nbLinks = (*itEL).second.size();
2167 if ( nbLinks < minNbLinks ) {
2168 startElem = (*itEL).first;
2169 minNbLinks = nbLinks;
2170 if ( minNbLinks == 1 )
2175 // search elements to fuse starting from startElem or links of elements
2176 // fused earlyer - startLinks
2177 list< SMESH_TLink > startLinks;
2178 while ( startElem || !startLinks.empty() ) {
2179 while ( !startElem && !startLinks.empty() ) {
2180 // Get an element to start, by a link
2181 SMESH_TLink linkId = startLinks.front();
2182 startLinks.pop_front();
2183 itLE = mapLi_listEl.find( linkId );
2184 if ( itLE != mapLi_listEl.end() ) {
2185 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2186 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2187 for ( ; itE != listElem.end() ; itE++ )
2188 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2190 mapLi_listEl.erase( itLE );
2195 // Get candidates to be fused
2196 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2197 const SMESH_TLink *link12, *link13;
2199 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2200 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2201 ASSERT( !setLi.empty() );
2202 set< SMESH_TLink >::iterator itLi;
2203 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2205 const SMESH_TLink & link = (*itLi);
2206 itLE = mapLi_listEl.find( link );
2207 if ( itLE == mapLi_listEl.end() )
2210 const SMDS_MeshElement* elem = (*itLE).second.front();
2212 elem = (*itLE).second.back();
2213 mapLi_listEl.erase( itLE );
2214 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2225 // add other links of elem to list of links to re-start from
2226 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2227 set< SMESH_TLink >::iterator it;
2228 for ( it = links.begin(); it != links.end(); it++ ) {
2229 const SMESH_TLink& link2 = (*it);
2230 if ( link2 != link )
2231 startLinks.push_back( link2 );
2235 // Get nodes of possible quadrangles
2236 const SMDS_MeshNode *n12 [4], *n13 [4];
2237 bool Ok12 = false, Ok13 = false;
2238 const SMDS_MeshNode *linkNode1, *linkNode2;
2240 linkNode1 = link12->first;
2241 linkNode2 = link12->second;
2242 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2246 linkNode1 = link13->first;
2247 linkNode2 = link13->second;
2248 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2252 // Choose a pair to fuse
2253 if ( Ok12 && Ok13 ) {
2254 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2255 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2256 double aBadRate12 = getBadRate( &quad12, theCrit );
2257 double aBadRate13 = getBadRate( &quad13, theCrit );
2258 if ( aBadRate13 < aBadRate12 )
2265 // and remove fused elems and removed links from the maps
2266 mapEl_setLi.erase( tr1 );
2268 mapEl_setLi.erase( tr2 );
2269 mapLi_listEl.erase( *link12 );
2270 if(tr1->NbNodes()==3) {
2271 const SMDS_MeshElement* newElem = 0;
2272 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2273 myLastCreatedElems.Append(newElem);
2274 AddToSameGroups( newElem, tr1, aMesh );
2275 int aShapeId = tr1->getshapeId();
2278 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2280 aMesh->RemoveElement( tr1 );
2281 aMesh->RemoveElement( tr2 );
2284 const SMDS_MeshNode* N1 [6];
2285 const SMDS_MeshNode* N2 [6];
2286 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2287 // now we receive following N1 and N2 (using numeration as above image)
2288 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2289 // i.e. first nodes from both arrays determ new diagonal
2290 const SMDS_MeshNode* aNodes[8];
2299 const SMDS_MeshElement* newElem = 0;
2300 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2301 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2302 myLastCreatedElems.Append(newElem);
2303 AddToSameGroups( newElem, tr1, aMesh );
2304 int aShapeId = tr1->getshapeId();
2307 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2309 aMesh->RemoveElement( tr1 );
2310 aMesh->RemoveElement( tr2 );
2311 // remove middle node (9)
2312 GetMeshDS()->RemoveNode( N1[4] );
2316 mapEl_setLi.erase( tr3 );
2317 mapLi_listEl.erase( *link13 );
2318 if(tr1->NbNodes()==3) {
2319 const SMDS_MeshElement* newElem = 0;
2320 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2321 myLastCreatedElems.Append(newElem);
2322 AddToSameGroups( newElem, tr1, aMesh );
2323 int aShapeId = tr1->getshapeId();
2326 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2328 aMesh->RemoveElement( tr1 );
2329 aMesh->RemoveElement( tr3 );
2332 const SMDS_MeshNode* N1 [6];
2333 const SMDS_MeshNode* N2 [6];
2334 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2335 // now we receive following N1 and N2 (using numeration as above image)
2336 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2337 // i.e. first nodes from both arrays determ new diagonal
2338 const SMDS_MeshNode* aNodes[8];
2347 const SMDS_MeshElement* newElem = 0;
2348 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2349 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2350 myLastCreatedElems.Append(newElem);
2351 AddToSameGroups( newElem, tr1, aMesh );
2352 int aShapeId = tr1->getshapeId();
2355 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2357 aMesh->RemoveElement( tr1 );
2358 aMesh->RemoveElement( tr3 );
2359 // remove middle node (9)
2360 GetMeshDS()->RemoveNode( N1[4] );
2364 // Next element to fuse: the rejected one
2366 startElem = Ok12 ? tr3 : tr2;
2368 } // if ( startElem )
2369 } // while ( startElem || !startLinks.empty() )
2370 } // while ( ! mapEl_setLi.empty() )
2376 /*#define DUMPSO(txt) \
2377 // cout << txt << endl;
2378 //=============================================================================
2382 //=============================================================================
2383 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2387 int tmp = idNodes[ i1 ];
2388 idNodes[ i1 ] = idNodes[ i2 ];
2389 idNodes[ i2 ] = tmp;
2390 gp_Pnt Ptmp = P[ i1 ];
2393 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2396 //=======================================================================
2397 //function : SortQuadNodes
2398 //purpose : Set 4 nodes of a quadrangle face in a good order.
2399 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2401 //=======================================================================
2403 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2408 for ( i = 0; i < 4; i++ ) {
2409 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2411 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2414 gp_Vec V1(P[0], P[1]);
2415 gp_Vec V2(P[0], P[2]);
2416 gp_Vec V3(P[0], P[3]);
2418 gp_Vec Cross1 = V1 ^ V2;
2419 gp_Vec Cross2 = V2 ^ V3;
2422 if (Cross1.Dot(Cross2) < 0)
2427 if (Cross1.Dot(Cross2) < 0)
2431 swap ( i, i + 1, idNodes, P );
2433 // for ( int ii = 0; ii < 4; ii++ ) {
2434 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2435 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2441 //=======================================================================
2442 //function : SortHexaNodes
2443 //purpose : Set 8 nodes of a hexahedron in a good order.
2444 // Return success status
2445 //=======================================================================
2447 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2452 DUMPSO( "INPUT: ========================================");
2453 for ( i = 0; i < 8; i++ ) {
2454 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2455 if ( !n ) return false;
2456 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2457 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2459 DUMPSO( "========================================");
2462 set<int> faceNodes; // ids of bottom face nodes, to be found
2463 set<int> checkedId1; // ids of tried 2-nd nodes
2464 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2465 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2466 int iMin, iLoop1 = 0;
2468 // Loop to try the 2-nd nodes
2470 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2472 // Find not checked 2-nd node
2473 for ( i = 1; i < 8; i++ )
2474 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2475 int id1 = idNodes[i];
2476 swap ( 1, i, idNodes, P );
2477 checkedId1.insert ( id1 );
2481 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2482 // ie that all but meybe one (id3 which is on the same face) nodes
2483 // lay on the same side from the triangle plane.
2485 bool manyInPlane = false; // more than 4 nodes lay in plane
2487 while ( ++iLoop2 < 6 ) {
2489 // get 1-2-3 plane coeffs
2490 Standard_Real A, B, C, D;
2491 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2492 if ( N.SquareMagnitude() > gp::Resolution() )
2494 gp_Pln pln ( P[0], N );
2495 pln.Coefficients( A, B, C, D );
2497 // find the node (iMin) closest to pln
2498 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2500 for ( i = 3; i < 8; i++ ) {
2501 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2502 if ( fabs( dist[i] ) < minDist ) {
2503 minDist = fabs( dist[i] );
2506 if ( fabs( dist[i] ) <= tol )
2507 idInPln.insert( idNodes[i] );
2510 // there should not be more than 4 nodes in bottom plane
2511 if ( idInPln.size() > 1 )
2513 DUMPSO( "### idInPln.size() = " << idInPln.size());
2514 // idInPlane does not contain the first 3 nodes
2515 if ( manyInPlane || idInPln.size() == 5)
2516 return false; // all nodes in one plane
2519 // set the 1-st node to be not in plane
2520 for ( i = 3; i < 8; i++ ) {
2521 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2522 DUMPSO( "### Reset 0-th node");
2523 swap( 0, i, idNodes, P );
2528 // reset to re-check second nodes
2529 leastDist = DBL_MAX;
2533 break; // from iLoop2;
2536 // check that the other 4 nodes are on the same side
2537 bool sameSide = true;
2538 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2539 for ( i = 3; sameSide && i < 8; i++ ) {
2541 sameSide = ( isNeg == dist[i] <= 0.);
2544 // keep best solution
2545 if ( sameSide && minDist < leastDist ) {
2546 leastDist = minDist;
2548 faceNodes.insert( idNodes[ 1 ] );
2549 faceNodes.insert( idNodes[ 2 ] );
2550 faceNodes.insert( idNodes[ iMin ] );
2551 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2552 << " leastDist = " << leastDist);
2553 if ( leastDist <= DBL_MIN )
2558 // set next 3-d node to check
2559 int iNext = 2 + iLoop2;
2561 DUMPSO( "Try 2-nd");
2562 swap ( 2, iNext, idNodes, P );
2564 } // while ( iLoop2 < 6 )
2567 if ( faceNodes.empty() ) return false;
2569 // Put the faceNodes in proper places
2570 for ( i = 4; i < 8; i++ ) {
2571 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2572 // find a place to put
2574 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2576 DUMPSO( "Set faceNodes");
2577 swap ( iTo, i, idNodes, P );
2582 // Set nodes of the found bottom face in good order
2583 DUMPSO( " Found bottom face: ");
2584 i = SortQuadNodes( theMesh, idNodes );
2586 gp_Pnt Ptmp = P[ i ];
2591 // for ( int ii = 0; ii < 4; ii++ ) {
2592 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2593 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2596 // Gravity center of the top and bottom faces
2597 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2598 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2600 // Get direction from the bottom to the top face
2601 gp_Vec upDir ( aGCb, aGCt );
2602 Standard_Real upDirSize = upDir.Magnitude();
2603 if ( upDirSize <= gp::Resolution() ) return false;
2606 // Assure that the bottom face normal points up
2607 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2608 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2609 if ( Nb.Dot( upDir ) < 0 ) {
2610 DUMPSO( "Reverse bottom face");
2611 swap( 1, 3, idNodes, P );
2614 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2615 Standard_Real minDist = DBL_MAX;
2616 for ( i = 4; i < 8; i++ ) {
2617 // projection of P[i] to the plane defined by P[0] and upDir
2618 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2619 Standard_Real sqDist = P[0].SquareDistance( Pp );
2620 if ( sqDist < minDist ) {
2625 DUMPSO( "Set 4-th");
2626 swap ( 4, iMin, idNodes, P );
2628 // Set nodes of the top face in good order
2629 DUMPSO( "Sort top face");
2630 i = SortQuadNodes( theMesh, &idNodes[4] );
2633 gp_Pnt Ptmp = P[ i ];
2638 // Assure that direction of the top face normal is from the bottom face
2639 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2640 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2641 if ( Nt.Dot( upDir ) < 0 ) {
2642 DUMPSO( "Reverse top face");
2643 swap( 5, 7, idNodes, P );
2646 // DUMPSO( "OUTPUT: ========================================");
2647 // for ( i = 0; i < 8; i++ ) {
2648 // float *p = ugrid->GetPoint(idNodes[i]);
2649 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2655 //================================================================================
2657 * \brief Return nodes linked to the given one
2658 * \param theNode - the node
2659 * \param linkedNodes - the found nodes
2660 * \param type - the type of elements to check
2662 * Medium nodes are ignored
2664 //================================================================================
2666 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2667 TIDSortedElemSet & linkedNodes,
2668 SMDSAbs_ElementType type )
2670 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2671 while ( elemIt->more() )
2673 const SMDS_MeshElement* elem = elemIt->next();
2674 if(elem->GetType() == SMDSAbs_0DElement)
2677 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2678 if ( elem->GetType() == SMDSAbs_Volume )
2680 SMDS_VolumeTool vol( elem );
2681 while ( nodeIt->more() ) {
2682 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2683 if ( theNode != n && vol.IsLinked( theNode, n ))
2684 linkedNodes.insert( n );
2689 for ( int i = 0; nodeIt->more(); ++i ) {
2690 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2691 if ( n == theNode ) {
2692 int iBefore = i - 1;
2694 if ( elem->IsQuadratic() ) {
2695 int nb = elem->NbNodes() / 2;
2696 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2697 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2699 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2700 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2707 //=======================================================================
2708 //function : laplacianSmooth
2709 //purpose : pulls theNode toward the center of surrounding nodes directly
2710 // connected to that node along an element edge
2711 //=======================================================================
2713 void laplacianSmooth(const SMDS_MeshNode* theNode,
2714 const Handle(Geom_Surface)& theSurface,
2715 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2717 // find surrounding nodes
2719 TIDSortedElemSet nodeSet;
2720 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2722 // compute new coodrs
2724 double coord[] = { 0., 0., 0. };
2725 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2726 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2727 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2728 if ( theSurface.IsNull() ) { // smooth in 3D
2729 coord[0] += node->X();
2730 coord[1] += node->Y();
2731 coord[2] += node->Z();
2733 else { // smooth in 2D
2734 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2735 gp_XY* uv = theUVMap[ node ];
2736 coord[0] += uv->X();
2737 coord[1] += uv->Y();
2740 int nbNodes = nodeSet.size();
2743 coord[0] /= nbNodes;
2744 coord[1] /= nbNodes;
2746 if ( !theSurface.IsNull() ) {
2747 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2748 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2749 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2755 coord[2] /= nbNodes;
2759 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2762 //=======================================================================
2763 //function : centroidalSmooth
2764 //purpose : pulls theNode toward the element-area-weighted centroid of the
2765 // surrounding elements
2766 //=======================================================================
2768 void centroidalSmooth(const SMDS_MeshNode* theNode,
2769 const Handle(Geom_Surface)& theSurface,
2770 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2772 gp_XYZ aNewXYZ(0.,0.,0.);
2773 SMESH::Controls::Area anAreaFunc;
2774 double totalArea = 0.;
2779 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2780 while ( elemIt->more() )
2782 const SMDS_MeshElement* elem = elemIt->next();
2785 gp_XYZ elemCenter(0.,0.,0.);
2786 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2787 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2788 int nn = elem->NbNodes();
2789 if(elem->IsQuadratic()) nn = nn/2;
2791 //while ( itN->more() ) {
2793 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2795 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2796 aNodePoints.push_back( aP );
2797 if ( !theSurface.IsNull() ) { // smooth in 2D
2798 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2799 gp_XY* uv = theUVMap[ aNode ];
2800 aP.SetCoord( uv->X(), uv->Y(), 0. );
2804 double elemArea = anAreaFunc.GetValue( aNodePoints );
2805 totalArea += elemArea;
2807 aNewXYZ += elemCenter * elemArea;
2809 aNewXYZ /= totalArea;
2810 if ( !theSurface.IsNull() ) {
2811 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2812 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2817 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2820 //=======================================================================
2821 //function : getClosestUV
2822 //purpose : return UV of closest projection
2823 //=======================================================================
2825 static bool getClosestUV (Extrema_GenExtPS& projector,
2826 const gp_Pnt& point,
2829 projector.Perform( point );
2830 if ( projector.IsDone() ) {
2831 double u, v, minVal = DBL_MAX;
2832 for ( int i = projector.NbExt(); i > 0; i-- )
2833 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2834 if ( projector.SquareDistance( i ) < minVal ) {
2835 minVal = projector.SquareDistance( i );
2837 if ( projector.Value( i ) < minVal ) {
2838 minVal = projector.Value( i );
2840 projector.Point( i ).Parameter( u, v );
2842 result.SetCoord( u, v );
2848 //=======================================================================
2850 //purpose : Smooth theElements during theNbIterations or until a worst
2851 // element has aspect ratio <= theTgtAspectRatio.
2852 // Aspect Ratio varies in range [1.0, inf].
2853 // If theElements is empty, the whole mesh is smoothed.
2854 // theFixedNodes contains additionally fixed nodes. Nodes built
2855 // on edges and boundary nodes are always fixed.
2856 //=======================================================================
2858 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2859 set<const SMDS_MeshNode*> & theFixedNodes,
2860 const SmoothMethod theSmoothMethod,
2861 const int theNbIterations,
2862 double theTgtAspectRatio,
2865 myLastCreatedElems.Clear();
2866 myLastCreatedNodes.Clear();
2868 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2870 if ( theTgtAspectRatio < 1.0 )
2871 theTgtAspectRatio = 1.0;
2873 const double disttol = 1.e-16;
2875 SMESH::Controls::AspectRatio aQualityFunc;
2877 SMESHDS_Mesh* aMesh = GetMeshDS();
2879 if ( theElems.empty() ) {
2880 // add all faces to theElems
2881 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2882 while ( fIt->more() ) {
2883 const SMDS_MeshElement* face = fIt->next();
2884 theElems.insert( face );
2887 // get all face ids theElems are on
2888 set< int > faceIdSet;
2889 TIDSortedElemSet::iterator itElem;
2891 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2892 int fId = FindShape( *itElem );
2893 // check that corresponding submesh exists and a shape is face
2895 faceIdSet.find( fId ) == faceIdSet.end() &&
2896 aMesh->MeshElements( fId )) {
2897 TopoDS_Shape F = aMesh->IndexToShape( fId );
2898 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2899 faceIdSet.insert( fId );
2902 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2904 // ===============================================
2905 // smooth elements on each TopoDS_Face separately
2906 // ===============================================
2908 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2909 for ( ; fId != faceIdSet.rend(); ++fId ) {
2910 // get face surface and submesh
2911 Handle(Geom_Surface) surface;
2912 SMESHDS_SubMesh* faceSubMesh = 0;
2914 double fToler2 = 0, f,l;
2915 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2916 bool isUPeriodic = false, isVPeriodic = false;
2918 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2919 surface = BRep_Tool::Surface( face );
2920 faceSubMesh = aMesh->MeshElements( *fId );
2921 fToler2 = BRep_Tool::Tolerance( face );
2922 fToler2 *= fToler2 * 10.;
2923 isUPeriodic = surface->IsUPeriodic();
2926 isVPeriodic = surface->IsVPeriodic();
2929 surface->Bounds( u1, u2, v1, v2 );
2931 // ---------------------------------------------------------
2932 // for elements on a face, find movable and fixed nodes and
2933 // compute UV for them
2934 // ---------------------------------------------------------
2935 bool checkBoundaryNodes = false;
2936 bool isQuadratic = false;
2937 set<const SMDS_MeshNode*> setMovableNodes;
2938 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2939 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2940 list< const SMDS_MeshElement* > elemsOnFace;
2942 Extrema_GenExtPS projector;
2943 GeomAdaptor_Surface surfAdaptor;
2944 if ( !surface.IsNull() ) {
2945 surfAdaptor.Load( surface );
2946 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2948 int nbElemOnFace = 0;
2949 itElem = theElems.begin();
2950 // loop on not yet smoothed elements: look for elems on a face
2951 while ( itElem != theElems.end() ) {
2952 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2953 break; // all elements found
2955 const SMDS_MeshElement* elem = *itElem;
2956 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2957 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2961 elemsOnFace.push_back( elem );
2962 theElems.erase( itElem++ );
2966 isQuadratic = elem->IsQuadratic();
2968 // get movable nodes of elem
2969 const SMDS_MeshNode* node;
2970 SMDS_TypeOfPosition posType;
2971 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2972 int nn = 0, nbn = elem->NbNodes();
2973 if(elem->IsQuadratic())
2975 while ( nn++ < nbn ) {
2976 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2977 const SMDS_PositionPtr& pos = node->GetPosition();
2978 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2979 if (posType != SMDS_TOP_EDGE &&
2980 posType != SMDS_TOP_VERTEX &&
2981 theFixedNodes.find( node ) == theFixedNodes.end())
2983 // check if all faces around the node are on faceSubMesh
2984 // because a node on edge may be bound to face
2985 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2987 if ( faceSubMesh ) {
2988 while ( eIt->more() && all ) {
2989 const SMDS_MeshElement* e = eIt->next();
2990 all = faceSubMesh->Contains( e );
2994 setMovableNodes.insert( node );
2996 checkBoundaryNodes = true;
2998 if ( posType == SMDS_TOP_3DSPACE )
2999 checkBoundaryNodes = true;
3002 if ( surface.IsNull() )
3005 // get nodes to check UV
3006 list< const SMDS_MeshNode* > uvCheckNodes;
3007 itN = elem->nodesIterator();
3008 nn = 0; nbn = elem->NbNodes();
3009 if(elem->IsQuadratic())
3011 while ( nn++ < nbn ) {
3012 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3013 if ( uvMap.find( node ) == uvMap.end() )
3014 uvCheckNodes.push_back( node );
3015 // add nodes of elems sharing node
3016 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3017 // while ( eIt->more() ) {
3018 // const SMDS_MeshElement* e = eIt->next();
3019 // if ( e != elem ) {
3020 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3021 // while ( nIt->more() ) {
3022 // const SMDS_MeshNode* n =
3023 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3024 // if ( uvMap.find( n ) == uvMap.end() )
3025 // uvCheckNodes.push_back( n );
3031 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3032 for ( ; n != uvCheckNodes.end(); ++n ) {
3035 const SMDS_PositionPtr& pos = node->GetPosition();
3036 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3038 switch ( posType ) {
3039 case SMDS_TOP_FACE: {
3040 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3041 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3044 case SMDS_TOP_EDGE: {
3045 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3046 Handle(Geom2d_Curve) pcurve;
3047 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3048 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3049 if ( !pcurve.IsNull() ) {
3050 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3051 uv = pcurve->Value( u ).XY();
3055 case SMDS_TOP_VERTEX: {
3056 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3057 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3058 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3063 // check existing UV
3064 bool project = true;
3065 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3066 double dist1 = DBL_MAX, dist2 = 0;
3067 if ( posType != SMDS_TOP_3DSPACE ) {
3068 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3069 project = dist1 > fToler2;
3071 if ( project ) { // compute new UV
3073 if ( !getClosestUV( projector, pNode, newUV )) {
3074 MESSAGE("Node Projection Failed " << node);
3078 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3080 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3082 if ( posType != SMDS_TOP_3DSPACE )
3083 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3084 if ( dist2 < dist1 )
3088 // store UV in the map
3089 listUV.push_back( uv );
3090 uvMap.insert( make_pair( node, &listUV.back() ));
3092 } // loop on not yet smoothed elements
3094 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3095 checkBoundaryNodes = true;
3097 // fix nodes on mesh boundary
3099 if ( checkBoundaryNodes ) {
3100 map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3101 map< SMESH_TLink, int >::iterator link_nb;
3102 // put all elements links to linkNbMap
3103 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3104 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3105 const SMDS_MeshElement* elem = (*elemIt);
3106 int nbn = elem->NbCornerNodes();
3107 // loop on elem links: insert them in linkNbMap
3108 for ( int iN = 0; iN < nbn; ++iN ) {
3109 const SMDS_MeshNode* n1 = elem->GetNode( iN );
3110 const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3111 SMESH_TLink link( n1, n2 );
3112 link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3116 // remove nodes that are in links encountered only once from setMovableNodes
3117 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3118 if ( link_nb->second == 1 ) {
3119 setMovableNodes.erase( link_nb->first.node1() );
3120 setMovableNodes.erase( link_nb->first.node2() );
3125 // -----------------------------------------------------
3126 // for nodes on seam edge, compute one more UV ( uvMap2 );
3127 // find movable nodes linked to nodes on seam and which
3128 // are to be smoothed using the second UV ( uvMap2 )
3129 // -----------------------------------------------------
3131 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3132 if ( !surface.IsNull() ) {
3133 TopExp_Explorer eExp( face, TopAbs_EDGE );
3134 for ( ; eExp.More(); eExp.Next() ) {
3135 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3136 if ( !BRep_Tool::IsClosed( edge, face ))
3138 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3139 if ( !sm ) continue;
3140 // find out which parameter varies for a node on seam
3143 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3144 if ( pcurve.IsNull() ) continue;
3145 uv1 = pcurve->Value( f );
3147 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3148 if ( pcurve.IsNull() ) continue;
3149 uv2 = pcurve->Value( f );
3150 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3152 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3153 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3155 // get nodes on seam and its vertices
3156 list< const SMDS_MeshNode* > seamNodes;
3157 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3158 while ( nSeamIt->more() ) {
3159 const SMDS_MeshNode* node = nSeamIt->next();
3160 if ( !isQuadratic || !IsMedium( node ))
3161 seamNodes.push_back( node );
3163 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3164 for ( ; vExp.More(); vExp.Next() ) {
3165 sm = aMesh->MeshElements( vExp.Current() );
3167 nSeamIt = sm->GetNodes();
3168 while ( nSeamIt->more() )
3169 seamNodes.push_back( nSeamIt->next() );
3172 // loop on nodes on seam
3173 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3174 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3175 const SMDS_MeshNode* nSeam = *noSeIt;
3176 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3177 if ( n_uv == uvMap.end() )
3180 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3181 // set the second UV
3182 listUV.push_back( *n_uv->second );
3183 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3184 if ( uvMap2.empty() )
3185 uvMap2 = uvMap; // copy the uvMap contents
3186 uvMap2[ nSeam ] = &listUV.back();
3188 // collect movable nodes linked to ones on seam in nodesNearSeam
3189 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3190 while ( eIt->more() ) {
3191 const SMDS_MeshElement* e = eIt->next();
3192 int nbUseMap1 = 0, nbUseMap2 = 0;
3193 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3194 int nn = 0, nbn = e->NbNodes();
3195 if(e->IsQuadratic()) nbn = nbn/2;
3196 while ( nn++ < nbn )
3198 const SMDS_MeshNode* n =
3199 static_cast<const SMDS_MeshNode*>( nIt->next() );
3201 setMovableNodes.find( n ) == setMovableNodes.end() )
3203 // add only nodes being closer to uv2 than to uv1
3204 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3205 0.5 * ( n->Y() + nSeam->Y() ),
3206 0.5 * ( n->Z() + nSeam->Z() ));
3208 getClosestUV( projector, pMid, uv );
3209 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3210 nodesNearSeam.insert( n );
3216 // for centroidalSmooth all element nodes must
3217 // be on one side of a seam
3218 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3219 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3221 while ( nn++ < nbn ) {
3222 const SMDS_MeshNode* n =
3223 static_cast<const SMDS_MeshNode*>( nIt->next() );
3224 setMovableNodes.erase( n );
3228 } // loop on nodes on seam
3229 } // loop on edge of a face
3230 } // if ( !face.IsNull() )
3232 if ( setMovableNodes.empty() ) {
3233 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3234 continue; // goto next face
3242 double maxRatio = -1., maxDisplacement = -1.;
3243 set<const SMDS_MeshNode*>::iterator nodeToMove;
3244 for ( it = 0; it < theNbIterations; it++ ) {
3245 maxDisplacement = 0.;
3246 nodeToMove = setMovableNodes.begin();
3247 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3248 const SMDS_MeshNode* node = (*nodeToMove);
3249 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3252 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3253 if ( theSmoothMethod == LAPLACIAN )
3254 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3256 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3258 // node displacement
3259 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3260 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3261 if ( aDispl > maxDisplacement )
3262 maxDisplacement = aDispl;
3264 // no node movement => exit
3265 //if ( maxDisplacement < 1.e-16 ) {
3266 if ( maxDisplacement < disttol ) {
3267 MESSAGE("-- no node movement --");
3271 // check elements quality
3273 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3274 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3275 const SMDS_MeshElement* elem = (*elemIt);
3276 if ( !elem || elem->GetType() != SMDSAbs_Face )
3278 SMESH::Controls::TSequenceOfXYZ aPoints;
3279 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3280 double aValue = aQualityFunc.GetValue( aPoints );
3281 if ( aValue > maxRatio )
3285 if ( maxRatio <= theTgtAspectRatio ) {
3286 MESSAGE("-- quality achived --");
3289 if (it+1 == theNbIterations) {
3290 MESSAGE("-- Iteration limit exceeded --");
3292 } // smoothing iterations
3294 MESSAGE(" Face id: " << *fId <<
3295 " Nb iterstions: " << it <<
3296 " Displacement: " << maxDisplacement <<
3297 " Aspect Ratio " << maxRatio);
3299 // ---------------------------------------
3300 // new nodes positions are computed,
3301 // record movement in DS and set new UV
3302 // ---------------------------------------
3303 nodeToMove = setMovableNodes.begin();
3304 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3305 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3306 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3307 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3308 if ( node_uv != uvMap.end() ) {
3309 gp_XY* uv = node_uv->second;
3311 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3315 // move medium nodes of quadratic elements
3318 SMESH_MesherHelper helper( *GetMesh() );
3319 if ( !face.IsNull() )
3320 helper.SetSubShape( face );
3321 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3322 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3323 const SMDS_VtkFace* QF =
3324 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3325 if(QF && QF->IsQuadratic()) {
3326 vector<const SMDS_MeshNode*> Ns;
3327 Ns.reserve(QF->NbNodes()+1);
3328 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3329 while ( anIter->more() )
3330 Ns.push_back( cast2Node(anIter->next()) );
3331 Ns.push_back( Ns[0] );
3333 for(int i=0; i<QF->NbNodes(); i=i+2) {
3334 if ( !surface.IsNull() ) {
3335 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3336 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3337 gp_XY uv = ( uv1 + uv2 ) / 2.;
3338 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3339 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3342 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3343 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3344 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3346 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3347 fabs( Ns[i+1]->Y() - y ) > disttol ||
3348 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3349 // we have to move i+1 node
3350 aMesh->MoveNode( Ns[i+1], x, y, z );
3357 } // loop on face ids
3361 //=======================================================================
3362 //function : isReverse
3363 //purpose : Return true if normal of prevNodes is not co-directied with
3364 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3365 // iNotSame is where prevNodes and nextNodes are different
3366 //=======================================================================
3368 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3369 vector<const SMDS_MeshNode*> nextNodes,
3373 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3374 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3376 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3377 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3378 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3379 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3381 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3382 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3383 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3384 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3386 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3388 return (vA ^ vB) * vN < 0.0;
3391 //=======================================================================
3393 * \brief Create elements by sweeping an element
3394 * \param elem - element to sweep
3395 * \param newNodesItVec - nodes generated from each node of the element
3396 * \param newElems - generated elements
3397 * \param nbSteps - number of sweeping steps
3398 * \param srcElements - to append elem for each generated element
3400 //=======================================================================
3402 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3403 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3404 list<const SMDS_MeshElement*>& newElems,
3406 SMESH_SequenceOfElemPtr& srcElements)
3408 //MESSAGE("sweepElement " << nbSteps);
3409 SMESHDS_Mesh* aMesh = GetMeshDS();
3411 // Loop on elem nodes:
3412 // find new nodes and detect same nodes indices
3413 int nbNodes = elem->NbNodes();
3414 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3415 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3416 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3417 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3419 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3420 vector<int> sames(nbNodes);
3421 vector<bool> issimple(nbNodes);
3423 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3424 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3425 const SMDS_MeshNode* node = nnIt->first;
3426 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3427 if ( listNewNodes.empty() ) {
3431 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3433 itNN[ iNode ] = listNewNodes.begin();
3434 prevNod[ iNode ] = node;
3435 nextNod[ iNode ] = listNewNodes.front();
3436 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3437 if ( prevNod[ iNode ] != nextNod [ iNode ])
3438 iNotSameNode = iNode;
3442 sames[nbSame++] = iNode;
3447 //cerr<<" nbSame = "<<nbSame<<endl;
3448 if ( nbSame == nbNodes || nbSame > 2) {
3449 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3450 //INFOS( " Too many same nodes of element " << elem->GetID() );
3454 // if( elem->IsQuadratic() && nbSame>0 ) {
3455 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3459 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3460 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3462 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3463 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3464 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3468 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3469 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3470 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3471 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3473 // check element orientation
3475 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3476 //MESSAGE("Reversed elem " << elem );
3480 std::swap( iBeforeSame, iAfterSame );
3483 // make new elements
3484 const SMDS_MeshElement* lastElem = elem;
3485 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3487 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3488 if(issimple[iNode]) {
3489 nextNod[ iNode ] = *itNN[ iNode ];
3493 if( elem->GetType()==SMDSAbs_Node ) {
3494 // we have to use two nodes
3495 midlNod[ iNode ] = *itNN[ iNode ];
3497 nextNod[ iNode ] = *itNN[ iNode ];
3500 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3501 // we have to use each second node
3503 nextNod[ iNode ] = *itNN[ iNode ];
3507 // we have to use two nodes
3508 midlNod[ iNode ] = *itNN[ iNode ];
3510 nextNod[ iNode ] = *itNN[ iNode ];
3515 SMDS_MeshElement* aNewElem = 0;
3516 if(!elem->IsPoly()) {
3517 switch ( nbNodes ) {
3521 if ( nbSame == 0 ) {
3523 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3525 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3531 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3532 nextNod[ 1 ], nextNod[ 0 ] );
3534 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3535 nextNod[ iNotSameNode ] );
3539 case 3: { // TRIANGLE or quadratic edge
3540 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3542 if ( nbSame == 0 ) // --- pentahedron
3543 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3544 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3546 else if ( nbSame == 1 ) // --- pyramid
3547 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3548 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3549 nextNod[ iSameNode ]);
3551 else // 2 same nodes: --- tetrahedron
3552 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3553 nextNod[ iNotSameNode ]);
3555 else { // quadratic edge
3556 if(nbSame==0) { // quadratic quadrangle
3557 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3558 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3560 else if(nbSame==1) { // quadratic triangle
3562 return; // medium node on axis
3564 else if(sames[0]==0) {
3565 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3566 nextNod[2], midlNod[1], prevNod[2]);
3568 else { // sames[0]==1
3569 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3570 midlNod[0], nextNod[2], prevNod[2]);
3579 case 4: { // QUADRANGLE
3581 if ( nbSame == 0 ) // --- hexahedron
3582 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3583 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3585 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3586 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3587 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3588 nextNod[ iSameNode ]);
3589 newElems.push_back( aNewElem );
3590 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3591 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3592 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3594 else if ( nbSame == 2 ) { // pentahedron
3595 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3596 // iBeforeSame is same too
3597 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3598 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3599 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3601 // iAfterSame is same too
3602 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3603 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3604 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3608 case 6: { // quadratic triangle
3609 // create pentahedron with 15 nodes
3611 if(i0>0) { // reversed case
3612 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3613 nextNod[0], nextNod[2], nextNod[1],
3614 prevNod[5], prevNod[4], prevNod[3],
3615 nextNod[5], nextNod[4], nextNod[3],
3616 midlNod[0], midlNod[2], midlNod[1]);
3618 else { // not reversed case
3619 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3620 nextNod[0], nextNod[1], nextNod[2],
3621 prevNod[3], prevNod[4], prevNod[5],
3622 nextNod[3], nextNod[4], nextNod[5],
3623 midlNod[0], midlNod[1], midlNod[2]);
3626 else if(nbSame==1) {
3627 // 2d order pyramid of 13 nodes
3628 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3629 // int n12,int n23,int n34,int n41,
3630 // int n15,int n25,int n35,int n45, int ID);
3632 int n1,n4,n41,n15,n45;
3633 if(i0>0) { // reversed case
3634 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3635 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3641 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3642 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3647 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3648 nextNod[n4], prevNod[n4], prevNod[n5],
3649 midlNod[n1], nextNod[n41],
3650 midlNod[n4], prevNod[n41],
3651 prevNod[n15], nextNod[n15],
3652 nextNod[n45], prevNod[n45]);
3654 else if(nbSame==2) {
3655 // 2d order tetrahedron of 10 nodes
3656 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3657 // int n12,int n23,int n31,
3658 // int n14,int n24,int n34, int ID);
3659 int n1 = iNotSameNode;
3660 int n2,n3,n12,n23,n31;
3661 if(i0>0) { // reversed case
3662 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3663 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3669 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3670 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3675 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3676 prevNod[n12], prevNod[n23], prevNod[n31],
3677 midlNod[n1], nextNod[n12], nextNod[n31]);
3681 case 8: { // quadratic quadrangle
3683 // create hexahedron with 20 nodes
3684 if(i0>0) { // reversed case
3685 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3686 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3687 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3688 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3689 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3691 else { // not reversed case
3692 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3693 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3694 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3695 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3696 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3699 else if(nbSame==1) {
3700 // --- pyramid + pentahedron - can not be created since it is needed
3701 // additional middle node ot the center of face
3702 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3705 else if(nbSame==2) {
3706 // 2d order Pentahedron with 15 nodes
3707 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3708 // int n12,int n23,int n31,int n45,int n56,int n64,
3709 // int n14,int n25,int n36, int ID);
3711 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3712 // iBeforeSame is same too
3719 // iAfterSame is same too
3725 int n12,n45,n14,n25;
3726 if(i0>0) { //reversed case
3738 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3739 prevNod[n4], prevNod[n5], nextNod[n5],
3740 prevNod[n12], midlNod[n2], nextNod[n12],
3741 prevNod[n45], midlNod[n5], nextNod[n45],
3742 prevNod[n14], prevNod[n25], nextNod[n25]);
3747 // realized for extrusion only
3748 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3749 //vector<int> quantities (nbNodes + 2);
3751 //quantities[0] = nbNodes; // bottom of prism
3752 //for (int inode = 0; inode < nbNodes; inode++) {
3753 // polyedre_nodes[inode] = prevNod[inode];
3756 //quantities[1] = nbNodes; // top of prism
3757 //for (int inode = 0; inode < nbNodes; inode++) {
3758 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3761 //for (int iface = 0; iface < nbNodes; iface++) {
3762 // quantities[iface + 2] = 4;
3763 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3764 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3765 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3766 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3767 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3769 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3776 // realized for extrusion only
3777 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3778 vector<int> quantities (nbNodes + 2);
3780 quantities[0] = nbNodes; // bottom of prism
3781 for (int inode = 0; inode < nbNodes; inode++) {
3782 polyedre_nodes[inode] = prevNod[inode];
3785 quantities[1] = nbNodes; // top of prism
3786 for (int inode = 0; inode < nbNodes; inode++) {
3787 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3790 for (int iface = 0; iface < nbNodes; iface++) {
3791 quantities[iface + 2] = 4;
3792 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3793 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3794 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3795 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3796 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3798 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3802 newElems.push_back( aNewElem );
3803 myLastCreatedElems.Append(aNewElem);
3804 srcElements.Append( elem );
3805 lastElem = aNewElem;
3808 // set new prev nodes
3809 for ( iNode = 0; iNode < nbNodes; iNode++ )
3810 prevNod[ iNode ] = nextNod[ iNode ];
3815 //=======================================================================
3817 * \brief Create 1D and 2D elements around swept elements
3818 * \param mapNewNodes - source nodes and ones generated from them
3819 * \param newElemsMap - source elements and ones generated from them
3820 * \param elemNewNodesMap - nodes generated from each node of each element
3821 * \param elemSet - all swept elements
3822 * \param nbSteps - number of sweeping steps
3823 * \param srcElements - to append elem for each generated element
3825 //=======================================================================
3827 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3828 TElemOfElemListMap & newElemsMap,
3829 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3830 TIDSortedElemSet& elemSet,
3832 SMESH_SequenceOfElemPtr& srcElements)
3834 MESSAGE("makeWalls");
3835 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3836 SMESHDS_Mesh* aMesh = GetMeshDS();
3838 // Find nodes belonging to only one initial element - sweep them to get edges.
3840 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3841 for ( ; nList != mapNewNodes.end(); nList++ ) {
3842 const SMDS_MeshNode* node =
3843 static_cast<const SMDS_MeshNode*>( nList->first );
3844 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3845 int nbInitElems = 0;
3846 const SMDS_MeshElement* el = 0;
3847 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3848 while ( eIt->more() && nbInitElems < 2 ) {
3850 SMDSAbs_ElementType type = el->GetType();
3851 if ( type == SMDSAbs_Volume || type < highType ) continue;
3852 if ( type > highType ) {
3856 if ( elemSet.find(el) != elemSet.end() )
3859 if ( nbInitElems < 2 ) {
3860 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3861 if(!NotCreateEdge) {
3862 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3863 list<const SMDS_MeshElement*> newEdges;
3864 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3869 // Make a ceiling for each element ie an equal element of last new nodes.
3870 // Find free links of faces - make edges and sweep them into faces.
3872 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3873 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3874 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3875 const SMDS_MeshElement* elem = itElem->first;
3876 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3878 if(itElem->second.size()==0) continue;
3880 if ( elem->GetType() == SMDSAbs_Edge ) {
3881 // create a ceiling edge
3882 if (!elem->IsQuadratic()) {
3883 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3884 vecNewNodes[ 1 ]->second.back())) {
3885 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3886 vecNewNodes[ 1 ]->second.back()));
3887 srcElements.Append( myLastCreatedElems.Last() );
3891 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3892 vecNewNodes[ 1 ]->second.back(),
3893 vecNewNodes[ 2 ]->second.back())) {
3894 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3895 vecNewNodes[ 1 ]->second.back(),
3896 vecNewNodes[ 2 ]->second.back()));
3897 srcElements.Append( myLastCreatedElems.Last() );
3901 if ( elem->GetType() != SMDSAbs_Face )
3904 bool hasFreeLinks = false;
3906 TIDSortedElemSet avoidSet;
3907 avoidSet.insert( elem );
3909 set<const SMDS_MeshNode*> aFaceLastNodes;
3910 int iNode, nbNodes = vecNewNodes.size();
3911 if(!elem->IsQuadratic()) {
3912 // loop on the face nodes
3913 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3914 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3915 // look for free links of the face
3916 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3917 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3918 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3919 // check if a link is free
3920 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3921 hasFreeLinks = true;
3922 // make an edge and a ceiling for a new edge
3923 if ( !aMesh->FindEdge( n1, n2 )) {
3924 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3925 srcElements.Append( myLastCreatedElems.Last() );
3927 n1 = vecNewNodes[ iNode ]->second.back();
3928 n2 = vecNewNodes[ iNext ]->second.back();
3929 if ( !aMesh->FindEdge( n1, n2 )) {
3930 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3931 srcElements.Append( myLastCreatedElems.Last() );
3936 else { // elem is quadratic face
3937 int nbn = nbNodes/2;
3938 for ( iNode = 0; iNode < nbn; iNode++ ) {
3939 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3940 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3941 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3942 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3943 // check if a link is free
3944 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3945 hasFreeLinks = true;
3946 // make an edge and a ceiling for a new edge
3948 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3949 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3950 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3951 srcElements.Append( myLastCreatedElems.Last() );
3953 n1 = vecNewNodes[ iNode ]->second.back();
3954 n2 = vecNewNodes[ iNext ]->second.back();
3955 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3956 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3957 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3958 srcElements.Append( myLastCreatedElems.Last() );
3962 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3963 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3967 // sweep free links into faces
3969 if ( hasFreeLinks ) {
3970 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3971 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3973 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3974 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3975 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3976 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3978 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3979 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3981 while ( iVol++ < volNb ) v++;
3982 // find indices of free faces of a volume and their source edges
3983 list< int > freeInd;
3984 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3985 SMDS_VolumeTool vTool( *v );
3986 int iF, nbF = vTool.NbFaces();
3987 for ( iF = 0; iF < nbF; iF ++ ) {
3988 if (vTool.IsFreeFace( iF ) &&
3989 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3990 initNodeSet != faceNodeSet) // except an initial face
3992 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3994 freeInd.push_back( iF );
3995 // find source edge of a free face iF
3996 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3997 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3998 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3999 initNodeSet.begin(), initNodeSet.end(),
4000 commonNodes.begin());
4001 if ( (*v)->IsQuadratic() )
4002 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4004 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4006 if ( !srcEdges.back() )
4008 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4009 << iF << " of volume #" << vTool.ID() << endl;
4014 if ( freeInd.empty() )
4017 // create faces for all steps;
4018 // if such a face has been already created by sweep of edge,
4019 // assure that its orientation is OK
4020 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4022 vTool.SetExternalNormal();
4023 const int nextShift = vTool.IsForward() ? +1 : -1;
4024 list< int >::iterator ind = freeInd.begin();
4025 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4026 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4028 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4029 int nbn = vTool.NbFaceNodes( *ind );
4030 if ( ! (*v)->IsPoly() )
4032 case 3: { ///// triangle
4033 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4035 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4037 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4039 nodes[ 1 + nextShift ] };
4041 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4043 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4048 case 4: { ///// quadrangle
4049 const SMDS_MeshFace * f =
4050 aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4052 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4054 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4055 nodes[ 2 ], nodes[ 2+nextShift ] };
4057 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4059 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4060 newOrder[ 2 ], newOrder[ 3 ]));
4064 case 6: { /////// quadratic triangle
4065 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4066 nodes[1], nodes[3], nodes[5] );
4068 nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4070 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4072 nodes[2 + 2*nextShift],
4073 nodes[3 - 2*nextShift],
4075 nodes[3 + 2*nextShift]};
4077 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4079 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4088 default: /////// quadratic quadrangle
4089 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4090 nodes[1], nodes[3], nodes[5], nodes[7] );
4092 nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4094 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4095 nodes[4 - 2*nextShift],
4097 nodes[4 + 2*nextShift],
4099 nodes[5 - 2*nextShift],
4101 nodes[5 + 2*nextShift] };
4103 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4105 myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4106 newOrder[ 2 ], newOrder[ 3 ],
4107 newOrder[ 4 ], newOrder[ 5 ],
4108 newOrder[ 6 ], newOrder[ 7 ]));
4112 else { //////// polygon
4114 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4115 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4117 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4119 if ( !vTool.IsForward() )
4120 std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4122 aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4124 AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4128 while ( srcElements.Length() < myLastCreatedElems.Length() )
4129 srcElements.Append( *srcEdge );
4131 } // loop on free faces
4133 // go to the next volume
4135 while ( iVol++ < nbVolumesByStep ) v++;
4138 } // loop on volumes of one step
4139 } // sweep free links into faces
4141 // Make a ceiling face with a normal external to a volume
4143 SMDS_VolumeTool lastVol( itElem->second.back() );
4145 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4147 lastVol.SetExternalNormal();
4148 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4149 int nbn = lastVol.NbFaceNodes( iF );
4152 if (!hasFreeLinks ||
4153 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4154 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4157 if (!hasFreeLinks ||
4158 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4159 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4162 if(itElem->second.back()->IsQuadratic()) {
4164 if (!hasFreeLinks ||
4165 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4166 nodes[1], nodes[3], nodes[5]) ) {
4167 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4168 nodes[1], nodes[3], nodes[5]));
4172 if (!hasFreeLinks ||
4173 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4174 nodes[1], nodes[3], nodes[5], nodes[7]) )
4175 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4176 nodes[1], nodes[3], nodes[5], nodes[7]));
4180 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4181 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4182 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4186 while ( srcElements.Length() < myLastCreatedElems.Length() )
4187 srcElements.Append( myLastCreatedElems.Last() );
4189 } // loop on swept elements
4192 //=======================================================================
4193 //function : RotationSweep
4195 //=======================================================================
4197 SMESH_MeshEditor::PGroupIDs
4198 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4199 const gp_Ax1& theAxis,
4200 const double theAngle,
4201 const int theNbSteps,
4202 const double theTol,
4203 const bool theMakeGroups,
4204 const bool theMakeWalls)
4206 myLastCreatedElems.Clear();
4207 myLastCreatedNodes.Clear();
4209 // source elements for each generated one
4210 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4212 MESSAGE( "RotationSweep()");
4214 aTrsf.SetRotation( theAxis, theAngle );
4216 aTrsf2.SetRotation( theAxis, theAngle/2. );
4218 gp_Lin aLine( theAxis );
4219 double aSqTol = theTol * theTol;
4221 SMESHDS_Mesh* aMesh = GetMeshDS();
4223 TNodeOfNodeListMap mapNewNodes;
4224 TElemOfVecOfNnlmiMap mapElemNewNodes;
4225 TElemOfElemListMap newElemsMap;
4228 TIDSortedElemSet::iterator itElem;
4229 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4230 const SMDS_MeshElement* elem = *itElem;
4231 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4233 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4234 newNodesItVec.reserve( elem->NbNodes() );
4236 // loop on elem nodes
4237 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4238 while ( itN->more() ) {
4239 // check if a node has been already sweeped
4240 const SMDS_MeshNode* node = cast2Node( itN->next() );
4242 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4244 aXYZ.Coord( coord[0], coord[1], coord[2] );
4245 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4247 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4248 if ( nIt == mapNewNodes.end() ) {
4249 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4250 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4253 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4255 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4256 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4257 const SMDS_MeshNode * newNode = node;
4258 for ( int i = 0; i < theNbSteps; i++ ) {
4260 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4262 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4263 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4264 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4265 myLastCreatedNodes.Append(newNode);
4266 srcNodes.Append( node );
4267 listNewNodes.push_back( newNode );
4268 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4269 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4272 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4274 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4275 myLastCreatedNodes.Append(newNode);
4276 srcNodes.Append( node );
4277 listNewNodes.push_back( newNode );
4280 listNewNodes.push_back( newNode );
4281 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4282 listNewNodes.push_back( newNode );
4289 // if current elem is quadratic and current node is not medium
4290 // we have to check - may be it is needed to insert additional nodes
4291 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4292 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4293 if(listNewNodes.size()==theNbSteps) {
4294 listNewNodes.clear();
4296 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4298 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4299 const SMDS_MeshNode * newNode = node;
4301 for(int i = 0; i<theNbSteps; i++) {
4302 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4303 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4304 cout<<" 3 AddNode: "<<newNode;
4305 myLastCreatedNodes.Append(newNode);
4306 listNewNodes.push_back( newNode );
4307 srcNodes.Append( node );
4308 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4309 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4310 cout<<" 4 AddNode: "<<newNode;
4311 myLastCreatedNodes.Append(newNode);
4312 srcNodes.Append( node );
4313 listNewNodes.push_back( newNode );
4317 listNewNodes.push_back( newNode );
4323 newNodesItVec.push_back( nIt );
4325 // make new elements
4326 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4330 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4332 PGroupIDs newGroupIDs;
4333 if ( theMakeGroups )
4334 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4340 //=======================================================================
4341 //function : CreateNode
4343 //=======================================================================
4344 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4347 const double tolnode,
4348 SMESH_SequenceOfNode& aNodes)
4350 myLastCreatedElems.Clear();
4351 myLastCreatedNodes.Clear();
4354 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4356 // try to search in sequence of existing nodes
4357 // if aNodes.Length()>0 we 'nave to use given sequence
4358 // else - use all nodes of mesh
4359 if(aNodes.Length()>0) {
4361 for(i=1; i<=aNodes.Length(); i++) {
4362 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4363 if(P1.Distance(P2)<tolnode)
4364 return aNodes.Value(i);
4368 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4369 while(itn->more()) {
4370 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4371 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4372 if(P1.Distance(P2)<tolnode)
4377 // create new node and return it
4378 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4379 myLastCreatedNodes.Append(NewNode);
4384 //=======================================================================
4385 //function : ExtrusionSweep
4387 //=======================================================================
4389 SMESH_MeshEditor::PGroupIDs
4390 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4391 const gp_Vec& theStep,
4392 const int theNbSteps,
4393 TElemOfElemListMap& newElemsMap,
4394 const bool theMakeGroups,
4396 const double theTolerance)
4398 ExtrusParam aParams;
4399 aParams.myDir = gp_Dir(theStep);
4400 aParams.myNodes.Clear();
4401 aParams.mySteps = new TColStd_HSequenceOfReal;
4403 for(i=1; i<=theNbSteps; i++)
4404 aParams.mySteps->Append(theStep.Magnitude());
4407 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4411 //=======================================================================
4412 //function : ExtrusionSweep
4414 //=======================================================================
4416 SMESH_MeshEditor::PGroupIDs
4417 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4418 ExtrusParam& theParams,
4419 TElemOfElemListMap& newElemsMap,
4420 const bool theMakeGroups,
4422 const double theTolerance)
4424 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4425 myLastCreatedElems.Clear();
4426 myLastCreatedNodes.Clear();
4428 // source elements for each generated one
4429 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4431 SMESHDS_Mesh* aMesh = GetMeshDS();
4433 int nbsteps = theParams.mySteps->Length();
4435 TNodeOfNodeListMap mapNewNodes;
4436 //TNodeOfNodeVecMap mapNewNodes;
4437 TElemOfVecOfNnlmiMap mapElemNewNodes;
4438 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4441 TIDSortedElemSet::iterator itElem;
4442 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4443 // check element type
4444 const SMDS_MeshElement* elem = *itElem;
4445 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4448 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4449 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4450 newNodesItVec.reserve( elem->NbNodes() );
4452 // loop on elem nodes
4453 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4454 while ( itN->more() )
4456 // check if a node has been already sweeped
4457 const SMDS_MeshNode* node = cast2Node( itN->next() );
4458 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4459 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4460 if ( nIt == mapNewNodes.end() ) {
4461 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4462 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4463 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4464 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4465 //vecNewNodes.reserve(nbsteps);
4468 double coord[] = { node->X(), node->Y(), node->Z() };
4469 //int nbsteps = theParams.mySteps->Length();
4470 for ( int i = 0; i < nbsteps; i++ ) {
4471 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4472 // create additional node
4473 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4474 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4475 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4476 if( theFlags & EXTRUSION_FLAG_SEW ) {
4477 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4478 theTolerance, theParams.myNodes);
4479 listNewNodes.push_back( newNode );
4482 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4483 myLastCreatedNodes.Append(newNode);
4484 srcNodes.Append( node );
4485 listNewNodes.push_back( newNode );
4488 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4489 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4490 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4491 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4492 if( theFlags & EXTRUSION_FLAG_SEW ) {
4493 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4494 theTolerance, theParams.myNodes);
4495 listNewNodes.push_back( newNode );
4496 //vecNewNodes[i]=newNode;
4499 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4500 myLastCreatedNodes.Append(newNode);
4501 srcNodes.Append( node );
4502 listNewNodes.push_back( newNode );
4503 //vecNewNodes[i]=newNode;
4508 // if current elem is quadratic and current node is not medium
4509 // we have to check - may be it is needed to insert additional nodes
4510 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4511 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4512 if(listNewNodes.size()==nbsteps) {
4513 listNewNodes.clear();
4514 double coord[] = { node->X(), node->Y(), node->Z() };
4515 for ( int i = 0; i < nbsteps; i++ ) {
4516 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4517 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4518 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4519 if( theFlags & EXTRUSION_FLAG_SEW ) {
4520 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4521 theTolerance, theParams.myNodes);
4522 listNewNodes.push_back( newNode );
4525 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4526 myLastCreatedNodes.Append(newNode);
4527 srcNodes.Append( node );
4528 listNewNodes.push_back( newNode );
4530 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4531 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4532 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4533 if( theFlags & EXTRUSION_FLAG_SEW ) {
4534 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4535 theTolerance, theParams.myNodes);
4536 listNewNodes.push_back( newNode );
4539 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4540 myLastCreatedNodes.Append(newNode);
4541 srcNodes.Append( node );
4542 listNewNodes.push_back( newNode );
4548 newNodesItVec.push_back( nIt );
4550 // make new elements
4551 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4554 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4555 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4557 PGroupIDs newGroupIDs;
4558 if ( theMakeGroups )
4559 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4565 //=======================================================================
4566 //class : SMESH_MeshEditor_PathPoint
4567 //purpose : auxiliary class
4568 //=======================================================================
4569 class SMESH_MeshEditor_PathPoint {
4571 SMESH_MeshEditor_PathPoint() {
4572 myPnt.SetCoord(99., 99., 99.);
4573 myTgt.SetCoord(1.,0.,0.);
4577 void SetPnt(const gp_Pnt& aP3D){
4580 void SetTangent(const gp_Dir& aTgt){
4583 void SetAngle(const double& aBeta){
4586 void SetParameter(const double& aPrm){
4589 const gp_Pnt& Pnt()const{
4592 const gp_Dir& Tangent()const{
4595 double Angle()const{
4598 double Parameter()const{
4610 //=======================================================================
4611 //function : ExtrusionAlongTrack
4613 //=======================================================================
4614 SMESH_MeshEditor::Extrusion_Error
4615 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4616 SMESH_subMesh* theTrack,
4617 const SMDS_MeshNode* theN1,
4618 const bool theHasAngles,
4619 list<double>& theAngles,
4620 const bool theLinearVariation,
4621 const bool theHasRefPoint,
4622 const gp_Pnt& theRefPoint,
4623 const bool theMakeGroups)
4625 MESSAGE("ExtrusionAlongTrack");
4626 myLastCreatedElems.Clear();
4627 myLastCreatedNodes.Clear();
4630 std::list<double> aPrms;
4631 TIDSortedElemSet::iterator itElem;
4634 TopoDS_Edge aTrackEdge;
4635 TopoDS_Vertex aV1, aV2;
4637 SMDS_ElemIteratorPtr aItE;
4638 SMDS_NodeIteratorPtr aItN;
4639 SMDSAbs_ElementType aTypeE;
4641 TNodeOfNodeListMap mapNewNodes;
4644 aNbE = theElements.size();
4647 return EXTR_NO_ELEMENTS;
4649 // 1.1 Track Pattern
4652 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4654 aItE = pSubMeshDS->GetElements();
4655 while ( aItE->more() ) {
4656 const SMDS_MeshElement* pE = aItE->next();
4657 aTypeE = pE->GetType();
4658 // Pattern must contain links only
4659 if ( aTypeE != SMDSAbs_Edge )
4660 return EXTR_PATH_NOT_EDGE;
4663 list<SMESH_MeshEditor_PathPoint> fullList;
4665 const TopoDS_Shape& aS = theTrack->GetSubShape();
4666 // Sub shape for the Pattern must be an Edge or Wire
4667 if( aS.ShapeType() == TopAbs_EDGE ) {
4668 aTrackEdge = TopoDS::Edge( aS );
4669 // the Edge must not be degenerated
4670 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4671 return EXTR_BAD_PATH_SHAPE;
4672 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4673 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4674 const SMDS_MeshNode* aN1 = aItN->next();
4675 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4676 const SMDS_MeshNode* aN2 = aItN->next();
4677 // starting node must be aN1 or aN2
4678 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4679 return EXTR_BAD_STARTING_NODE;
4680 aItN = pSubMeshDS->GetNodes();
4681 while ( aItN->more() ) {
4682 const SMDS_MeshNode* pNode = aItN->next();
4683 const SMDS_EdgePosition* pEPos =
4684 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4685 double aT = pEPos->GetUParameter();
4686 aPrms.push_back( aT );
4688 //Extrusion_Error err =
4689 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4691 else if( aS.ShapeType() == TopAbs_WIRE ) {
4692 list< SMESH_subMesh* > LSM;
4693 TopTools_SequenceOfShape Edges;
4694 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4695 while(itSM->more()) {
4696 SMESH_subMesh* SM = itSM->next();
4698 const TopoDS_Shape& aS = SM->GetSubShape();
4701 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4702 int startNid = theN1->GetID();
4703 TColStd_MapOfInteger UsedNums;
4704 int NbEdges = Edges.Length();
4706 for(; i<=NbEdges; i++) {
4708 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4709 for(; itLSM!=LSM.end(); itLSM++) {
4711 if(UsedNums.Contains(k)) continue;
4712 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4713 SMESH_subMesh* locTrack = *itLSM;
4714 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4715 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4716 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4717 const SMDS_MeshNode* aN1 = aItN->next();
4718 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4719 const SMDS_MeshNode* aN2 = aItN->next();
4720 // starting node must be aN1 or aN2
4721 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4722 // 2. Collect parameters on the track edge
4724 aItN = locMeshDS->GetNodes();
4725 while ( aItN->more() ) {
4726 const SMDS_MeshNode* pNode = aItN->next();
4727 const SMDS_EdgePosition* pEPos =
4728 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4729 double aT = pEPos->GetUParameter();
4730 aPrms.push_back( aT );
4732 list<SMESH_MeshEditor_PathPoint> LPP;
4733 //Extrusion_Error err =
4734 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4735 LLPPs.push_back(LPP);
4737 // update startN for search following egde
4738 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4739 else startNid = aN1->GetID();
4743 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4744 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4745 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4746 for(; itPP!=firstList.end(); itPP++) {
4747 fullList.push_back( *itPP );
4749 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4750 fullList.pop_back();
4752 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4753 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4754 itPP = currList.begin();
4755 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4756 gp_Dir D1 = PP1.Tangent();
4757 gp_Dir D2 = PP2.Tangent();
4758 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4759 (D1.Z()+D2.Z())/2 ) );
4760 PP1.SetTangent(Dnew);
4761 fullList.push_back(PP1);
4763 for(; itPP!=firstList.end(); itPP++) {
4764 fullList.push_back( *itPP );
4766 PP1 = fullList.back();
4767 fullList.pop_back();
4769 // if wire not closed
4770 fullList.push_back(PP1);
4774 return EXTR_BAD_PATH_SHAPE;
4777 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4778 theHasRefPoint, theRefPoint, theMakeGroups);
4782 //=======================================================================
4783 //function : ExtrusionAlongTrack
4785 //=======================================================================
4786 SMESH_MeshEditor::Extrusion_Error
4787 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4788 SMESH_Mesh* theTrack,
4789 const SMDS_MeshNode* theN1,
4790 const bool theHasAngles,
4791 list<double>& theAngles,
4792 const bool theLinearVariation,
4793 const bool theHasRefPoint,
4794 const gp_Pnt& theRefPoint,
4795 const bool theMakeGroups)
4797 myLastCreatedElems.Clear();
4798 myLastCreatedNodes.Clear();
4801 std::list<double> aPrms;
4802 TIDSortedElemSet::iterator itElem;
4805 TopoDS_Edge aTrackEdge;
4806 TopoDS_Vertex aV1, aV2;
4808 SMDS_ElemIteratorPtr aItE;
4809 SMDS_NodeIteratorPtr aItN;
4810 SMDSAbs_ElementType aTypeE;
4812 TNodeOfNodeListMap mapNewNodes;
4815 aNbE = theElements.size();
4818 return EXTR_NO_ELEMENTS;
4820 // 1.1 Track Pattern
4823 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4825 aItE = pMeshDS->elementsIterator();
4826 while ( aItE->more() ) {
4827 const SMDS_MeshElement* pE = aItE->next();
4828 aTypeE = pE->GetType();
4829 // Pattern must contain links only
4830 if ( aTypeE != SMDSAbs_Edge )
4831 return EXTR_PATH_NOT_EDGE;
4834 list<SMESH_MeshEditor_PathPoint> fullList;
4836 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4837 // Sub shape for the Pattern must be an Edge or Wire
4838 if( aS.ShapeType() == TopAbs_EDGE ) {
4839 aTrackEdge = TopoDS::Edge( aS );
4840 // the Edge must not be degenerated
4841 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4842 return EXTR_BAD_PATH_SHAPE;
4843 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4844 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4845 const SMDS_MeshNode* aN1 = aItN->next();
4846 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4847 const SMDS_MeshNode* aN2 = aItN->next();
4848 // starting node must be aN1 or aN2
4849 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4850 return EXTR_BAD_STARTING_NODE;
4851 aItN = pMeshDS->nodesIterator();
4852 while ( aItN->more() ) {
4853 const SMDS_MeshNode* pNode = aItN->next();
4854 if( pNode==aN1 || pNode==aN2 ) continue;
4855 const SMDS_EdgePosition* pEPos =
4856 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4857 double aT = pEPos->GetUParameter();
4858 aPrms.push_back( aT );
4860 //Extrusion_Error err =
4861 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4863 else if( aS.ShapeType() == TopAbs_WIRE ) {
4864 list< SMESH_subMesh* > LSM;
4865 TopTools_SequenceOfShape Edges;
4866 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4867 for(; eExp.More(); eExp.Next()) {
4868 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4869 if( BRep_Tool::Degenerated(E) ) continue;
4870 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4876 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4877 int startNid = theN1->GetID();
4878 TColStd_MapOfInteger UsedNums;
4879 int NbEdges = Edges.Length();
4881 for(; i<=NbEdges; i++) {
4883 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4884 for(; itLSM!=LSM.end(); itLSM++) {
4886 if(UsedNums.Contains(k)) continue;
4887 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4888 SMESH_subMesh* locTrack = *itLSM;
4889 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4890 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4891 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4892 const SMDS_MeshNode* aN1 = aItN->next();
4893 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4894 const SMDS_MeshNode* aN2 = aItN->next();
4895 // starting node must be aN1 or aN2
4896 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4897 // 2. Collect parameters on the track edge
4899 aItN = locMeshDS->GetNodes();
4900 while ( aItN->more() ) {
4901 const SMDS_MeshNode* pNode = aItN->next();
4902 const SMDS_EdgePosition* pEPos =
4903 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4904 double aT = pEPos->GetUParameter();
4905 aPrms.push_back( aT );
4907 list<SMESH_MeshEditor_PathPoint> LPP;
4908 //Extrusion_Error err =
4909 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4910 LLPPs.push_back(LPP);
4912 // update startN for search following egde
4913 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4914 else startNid = aN1->GetID();
4918 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4919 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4920 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4921 for(; itPP!=firstList.end(); itPP++) {
4922 fullList.push_back( *itPP );
4924 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4925 fullList.pop_back();
4927 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4928 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4929 itPP = currList.begin();
4930 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4931 gp_Dir D1 = PP1.Tangent();
4932 gp_Dir D2 = PP2.Tangent();
4933 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4934 (D1.Z()+D2.Z())/2 ) );
4935 PP1.SetTangent(Dnew);
4936 fullList.push_back(PP1);
4938 for(; itPP!=currList.end(); itPP++) {
4939 fullList.push_back( *itPP );
4941 PP1 = fullList.back();
4942 fullList.pop_back();
4944 // if wire not closed
4945 fullList.push_back(PP1);
4949 return EXTR_BAD_PATH_SHAPE;
4952 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4953 theHasRefPoint, theRefPoint, theMakeGroups);
4957 //=======================================================================
4958 //function : MakeEdgePathPoints
4959 //purpose : auxilary for ExtrusionAlongTrack
4960 //=======================================================================
4961 SMESH_MeshEditor::Extrusion_Error
4962 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4963 const TopoDS_Edge& aTrackEdge,
4965 list<SMESH_MeshEditor_PathPoint>& LPP)
4967 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4969 aTolVec2=aTolVec*aTolVec;
4971 TopoDS_Vertex aV1, aV2;
4972 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4973 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4974 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4975 // 2. Collect parameters on the track edge
4976 aPrms.push_front( aT1 );
4977 aPrms.push_back( aT2 );
4980 if( FirstIsStart ) {
4991 SMESH_MeshEditor_PathPoint aPP;
4992 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4993 std::list<double>::iterator aItD = aPrms.begin();
4994 for(; aItD != aPrms.end(); ++aItD) {
4998 aC3D->D1( aT, aP3D, aVec );
4999 aL2 = aVec.SquareMagnitude();
5000 if ( aL2 < aTolVec2 )
5001 return EXTR_CANT_GET_TANGENT;
5002 gp_Dir aTgt( aVec );
5004 aPP.SetTangent( aTgt );
5005 aPP.SetParameter( aT );
5012 //=======================================================================
5013 //function : MakeExtrElements
5014 //purpose : auxilary for ExtrusionAlongTrack
5015 //=======================================================================
5016 SMESH_MeshEditor::Extrusion_Error
5017 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5018 list<SMESH_MeshEditor_PathPoint>& fullList,
5019 const bool theHasAngles,
5020 list<double>& theAngles,
5021 const bool theLinearVariation,
5022 const bool theHasRefPoint,
5023 const gp_Pnt& theRefPoint,
5024 const bool theMakeGroups)
5026 MESSAGE("MakeExtrElements");
5027 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5028 int aNbTP = fullList.size();
5029 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5031 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5032 LinearAngleVariation(aNbTP-1, theAngles);
5034 vector<double> aAngles( aNbTP );
5036 for(; j<aNbTP; ++j) {
5039 if ( theHasAngles ) {
5041 std::list<double>::iterator aItD = theAngles.begin();
5042 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5044 aAngles[j] = anAngle;
5047 // fill vector of path points with angles
5048 //aPPs.resize(fullList.size());
5050 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5051 for(; itPP!=fullList.end(); itPP++) {
5053 SMESH_MeshEditor_PathPoint PP = *itPP;
5054 PP.SetAngle(aAngles[j]);
5058 TNodeOfNodeListMap mapNewNodes;
5059 TElemOfVecOfNnlmiMap mapElemNewNodes;
5060 TElemOfElemListMap newElemsMap;
5061 TIDSortedElemSet::iterator itElem;
5064 SMDSAbs_ElementType aTypeE;
5065 // source elements for each generated one
5066 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5068 // 3. Center of rotation aV0
5069 gp_Pnt aV0 = theRefPoint;
5071 if ( !theHasRefPoint ) {
5073 aGC.SetCoord( 0.,0.,0. );
5075 itElem = theElements.begin();
5076 for ( ; itElem != theElements.end(); itElem++ ) {
5077 const SMDS_MeshElement* elem = *itElem;
5079 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5080 while ( itN->more() ) {
5081 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5086 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5087 list<const SMDS_MeshNode*> aLNx;
5088 mapNewNodes[node] = aLNx;
5090 gp_XYZ aXYZ( aX, aY, aZ );
5098 } // if (!theHasRefPoint) {
5099 mapNewNodes.clear();
5101 // 4. Processing the elements
5102 SMESHDS_Mesh* aMesh = GetMeshDS();
5104 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5105 // check element type
5106 const SMDS_MeshElement* elem = *itElem;
5107 aTypeE = elem->GetType();
5108 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5111 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5112 newNodesItVec.reserve( elem->NbNodes() );
5114 // loop on elem nodes
5116 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5117 while ( itN->more() )
5120 // check if a node has been already processed
5121 const SMDS_MeshNode* node =
5122 static_cast<const SMDS_MeshNode*>( itN->next() );
5123 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5124 if ( nIt == mapNewNodes.end() ) {
5125 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5126 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5129 aX = node->X(); aY = node->Y(); aZ = node->Z();
5131 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5132 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5133 gp_Ax1 anAx1, anAxT1T0;
5134 gp_Dir aDT1x, aDT0x, aDT1T0;
5139 aPN0.SetCoord(aX, aY, aZ);
5141 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5143 aDT0x= aPP0.Tangent();
5144 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5146 for ( j = 1; j < aNbTP; ++j ) {
5147 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5149 aDT1x = aPP1.Tangent();
5150 aAngle1x = aPP1.Angle();
5152 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5154 gp_Vec aV01x( aP0x, aP1x );
5155 aTrsf.SetTranslation( aV01x );
5158 aV1x = aV0x.Transformed( aTrsf );
5159 aPN1 = aPN0.Transformed( aTrsf );
5161 // rotation 1 [ T1,T0 ]
5162 aAngleT1T0=-aDT1x.Angle( aDT0x );
5163 if (fabs(aAngleT1T0) > aTolAng) {
5165 anAxT1T0.SetLocation( aV1x );
5166 anAxT1T0.SetDirection( aDT1T0 );
5167 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5169 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5173 if ( theHasAngles ) {
5174 anAx1.SetLocation( aV1x );
5175 anAx1.SetDirection( aDT1x );
5176 aTrsfRot.SetRotation( anAx1, aAngle1x );
5178 aPN1 = aPN1.Transformed( aTrsfRot );
5182 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5183 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5184 // create additional node
5185 double x = ( aPN1.X() + aPN0.X() )/2.;
5186 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5187 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5188 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5189 myLastCreatedNodes.Append(newNode);
5190 srcNodes.Append( node );
5191 listNewNodes.push_back( newNode );
5196 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5197 myLastCreatedNodes.Append(newNode);
5198 srcNodes.Append( node );
5199 listNewNodes.push_back( newNode );
5209 // if current elem is quadratic and current node is not medium
5210 // we have to check - may be it is needed to insert additional nodes
5211 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5212 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5213 if(listNewNodes.size()==aNbTP-1) {
5214 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5215 gp_XYZ P(node->X(), node->Y(), node->Z());
5216 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5218 for(i=0; i<aNbTP-1; i++) {
5219 const SMDS_MeshNode* N = *it;
5220 double x = ( N->X() + P.X() )/2.;
5221 double y = ( N->Y() + P.Y() )/2.;
5222 double z = ( N->Z() + P.Z() )/2.;
5223 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5224 srcNodes.Append( node );
5225 myLastCreatedNodes.Append(newN);
5228 P = gp_XYZ(N->X(),N->Y(),N->Z());
5230 listNewNodes.clear();
5231 for(i=0; i<2*(aNbTP-1); i++) {
5232 listNewNodes.push_back(aNodes[i]);
5238 newNodesItVec.push_back( nIt );
5240 // make new elements
5241 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5242 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5243 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5246 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5248 if ( theMakeGroups )
5249 generateGroups( srcNodes, srcElems, "extruded");
5255 //=======================================================================
5256 //function : LinearAngleVariation
5257 //purpose : auxilary for ExtrusionAlongTrack
5258 //=======================================================================
5259 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5260 list<double>& Angles)
5262 int nbAngles = Angles.size();
5263 if( nbSteps > nbAngles ) {
5264 vector<double> theAngles(nbAngles);
5265 list<double>::iterator it = Angles.begin();
5267 for(; it!=Angles.end(); it++) {
5269 theAngles[i] = (*it);
5272 double rAn2St = double( nbAngles ) / double( nbSteps );
5273 double angPrev = 0, angle;
5274 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5275 double angCur = rAn2St * ( iSt+1 );
5276 double angCurFloor = floor( angCur );
5277 double angPrevFloor = floor( angPrev );
5278 if ( angPrevFloor == angCurFloor )
5279 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5281 int iP = int( angPrevFloor );
5282 double angPrevCeil = ceil(angPrev);
5283 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5285 int iC = int( angCurFloor );
5286 if ( iC < nbAngles )
5287 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5289 iP = int( angPrevCeil );
5291 angle += theAngles[ iC ];
5293 res.push_back(angle);
5298 for(; it!=res.end(); it++)
5299 Angles.push_back( *it );
5304 //================================================================================
5306 * \brief Move or copy theElements applying theTrsf to their nodes
5307 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5308 * \param theTrsf - transformation to apply
5309 * \param theCopy - if true, create translated copies of theElems
5310 * \param theMakeGroups - if true and theCopy, create translated groups
5311 * \param theTargetMesh - mesh to copy translated elements into
5312 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5314 //================================================================================
5316 SMESH_MeshEditor::PGroupIDs
5317 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5318 const gp_Trsf& theTrsf,
5320 const bool theMakeGroups,
5321 SMESH_Mesh* theTargetMesh)
5323 myLastCreatedElems.Clear();
5324 myLastCreatedNodes.Clear();
5326 bool needReverse = false;
5327 string groupPostfix;
5328 switch ( theTrsf.Form() ) {
5330 MESSAGE("gp_PntMirror");
5332 groupPostfix = "mirrored";
5335 MESSAGE("gp_Ax1Mirror");
5336 groupPostfix = "mirrored";
5339 MESSAGE("gp_Ax2Mirror");
5341 groupPostfix = "mirrored";
5344 MESSAGE("gp_Rotation");
5345 groupPostfix = "rotated";
5347 case gp_Translation:
5348 MESSAGE("gp_Translation");
5349 groupPostfix = "translated";
5352 MESSAGE("gp_Scale");
5353 groupPostfix = "scaled";
5355 case gp_CompoundTrsf: // different scale by axis
5356 MESSAGE("gp_CompoundTrsf");
5357 groupPostfix = "scaled";
5361 needReverse = false;
5362 groupPostfix = "transformed";
5365 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5366 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5367 SMESHDS_Mesh* aMesh = GetMeshDS();
5370 // map old node to new one
5371 TNodeNodeMap nodeMap;
5373 // elements sharing moved nodes; those of them which have all
5374 // nodes mirrored but are not in theElems are to be reversed
5375 TIDSortedElemSet inverseElemSet;
5377 // source elements for each generated one
5378 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5380 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5381 TIDSortedElemSet orphanNode;
5383 if ( theElems.empty() ) // transform the whole mesh
5386 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5387 while ( eIt->more() ) theElems.insert( eIt->next() );
5389 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5390 while ( nIt->more() )
5392 const SMDS_MeshNode* node = nIt->next();
5393 if ( node->NbInverseElements() == 0)
5394 orphanNode.insert( node );
5398 // loop on elements to transform nodes : first orphan nodes then elems
5399 TIDSortedElemSet::iterator itElem;
5400 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5401 for (int i=0; i<2; i++)
5402 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5403 const SMDS_MeshElement* elem = *itElem;
5407 // loop on elem nodes
5408 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5409 while ( itN->more() ) {
5411 const SMDS_MeshNode* node = cast2Node( itN->next() );
5412 // check if a node has been already transformed
5413 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5414 nodeMap.insert( make_pair ( node, node ));
5415 if ( !n2n_isnew.second )
5419 coord[0] = node->X();
5420 coord[1] = node->Y();
5421 coord[2] = node->Z();
5422 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5423 if ( theTargetMesh ) {
5424 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5425 n2n_isnew.first->second = newNode;
5426 myLastCreatedNodes.Append(newNode);
5427 srcNodes.Append( node );
5429 else if ( theCopy ) {
5430 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5431 n2n_isnew.first->second = newNode;
5432 myLastCreatedNodes.Append(newNode);
5433 srcNodes.Append( node );
5436 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5437 // node position on shape becomes invalid
5438 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5439 ( SMDS_SpacePosition::originSpacePosition() );
5442 // keep inverse elements
5443 if ( !theCopy && !theTargetMesh && needReverse ) {
5444 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5445 while ( invElemIt->more() ) {
5446 const SMDS_MeshElement* iel = invElemIt->next();
5447 inverseElemSet.insert( iel );
5453 // either create new elements or reverse mirrored ones
5454 if ( !theCopy && !needReverse && !theTargetMesh )
5457 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5458 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5459 theElems.insert( *invElemIt );
5461 // replicate or reverse elements
5462 // TODO revoir ordre reverse vtk
5464 REV_TETRA = 0, // = nbNodes - 4
5465 REV_PYRAMID = 1, // = nbNodes - 4
5466 REV_PENTA = 2, // = nbNodes - 4
5468 REV_HEXA = 4, // = nbNodes - 4
5472 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5473 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5474 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5475 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5476 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5477 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5480 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5482 const SMDS_MeshElement* elem = *itElem;
5483 if ( !elem || elem->GetType() == SMDSAbs_Node )
5486 int nbNodes = elem->NbNodes();
5487 int elemType = elem->GetType();
5489 if (elem->IsPoly()) {
5490 // Polygon or Polyhedral Volume
5491 switch ( elemType ) {
5494 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5496 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5497 while (itN->more()) {
5498 const SMDS_MeshNode* node =
5499 static_cast<const SMDS_MeshNode*>(itN->next());
5500 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5501 if (nodeMapIt == nodeMap.end())
5502 break; // not all nodes transformed
5504 // reverse mirrored faces and volumes
5505 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5507 poly_nodes[iNode] = (*nodeMapIt).second;
5511 if ( iNode != nbNodes )
5512 continue; // not all nodes transformed
5514 if ( theTargetMesh ) {
5515 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5516 srcElems.Append( elem );
5518 else if ( theCopy ) {
5519 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5520 srcElems.Append( elem );
5523 aMesh->ChangePolygonNodes(elem, poly_nodes);
5527 case SMDSAbs_Volume:
5529 // ATTENTION: Reversing is not yet done!!!
5530 const SMDS_VtkVolume* aPolyedre =
5531 dynamic_cast<const SMDS_VtkVolume*>( elem );
5533 MESSAGE("Warning: bad volumic element");
5537 vector<const SMDS_MeshNode*> poly_nodes;
5538 vector<int> quantities;
5540 bool allTransformed = true;
5541 int nbFaces = aPolyedre->NbFaces();
5542 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5543 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5544 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5545 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5546 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5547 if (nodeMapIt == nodeMap.end()) {
5548 allTransformed = false; // not all nodes transformed
5550 poly_nodes.push_back((*nodeMapIt).second);
5553 quantities.push_back(nbFaceNodes);
5555 if ( !allTransformed )
5556 continue; // not all nodes transformed
5558 if ( theTargetMesh ) {
5559 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5560 srcElems.Append( elem );
5562 else if ( theCopy ) {
5563 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5564 srcElems.Append( elem );
5567 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5577 int* i = index[ FORWARD ];
5578 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5579 if ( elemType == SMDSAbs_Face )
5580 i = index[ REV_FACE ];
5582 i = index[ nbNodes - 4 ];
5584 if(elem->IsQuadratic()) {
5585 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5588 if(nbNodes==3) { // quadratic edge
5589 static int anIds[] = {1,0,2};
5592 else if(nbNodes==6) { // quadratic triangle
5593 static int anIds[] = {0,2,1,5,4,3};
5596 else if(nbNodes==8) { // quadratic quadrangle
5597 static int anIds[] = {0,3,2,1,7,6,5,4};
5600 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5601 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5604 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5605 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5608 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5609 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5612 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5613 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5619 // find transformed nodes
5620 vector<const SMDS_MeshNode*> nodes(nbNodes);
5622 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5623 while ( itN->more() ) {
5624 const SMDS_MeshNode* node =
5625 static_cast<const SMDS_MeshNode*>( itN->next() );
5626 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5627 if ( nodeMapIt == nodeMap.end() )
5628 break; // not all nodes transformed
5629 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5631 if ( iNode != nbNodes )
5632 continue; // not all nodes transformed
5634 if ( theTargetMesh ) {
5635 if ( SMDS_MeshElement* copy =
5636 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5637 myLastCreatedElems.Append( copy );
5638 srcElems.Append( elem );
5641 else if ( theCopy ) {
5642 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5643 srcElems.Append( elem );
5646 // reverse element as it was reversed by transformation
5648 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5652 PGroupIDs newGroupIDs;
5654 if ( ( theMakeGroups && theCopy ) ||
5655 ( theMakeGroups && theTargetMesh ) )
5656 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5662 ////=======================================================================
5663 ////function : Scale
5665 ////=======================================================================
5667 //SMESH_MeshEditor::PGroupIDs
5668 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5669 // const gp_Pnt& thePoint,
5670 // const std::list<double>& theScaleFact,
5671 // const bool theCopy,
5672 // const bool theMakeGroups,
5673 // SMESH_Mesh* theTargetMesh)
5675 // MESSAGE("Scale");
5676 // myLastCreatedElems.Clear();
5677 // myLastCreatedNodes.Clear();
5679 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5680 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5681 // SMESHDS_Mesh* aMesh = GetMeshDS();
5683 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5684 // std::list<double>::const_iterator itS = theScaleFact.begin();
5686 // if(theScaleFact.size()==1) {
5690 // if(theScaleFact.size()==2) {
5695 // if(theScaleFact.size()>2) {
5702 // // map old node to new one
5703 // TNodeNodeMap nodeMap;
5705 // // elements sharing moved nodes; those of them which have all
5706 // // nodes mirrored but are not in theElems are to be reversed
5707 // TIDSortedElemSet inverseElemSet;
5709 // // source elements for each generated one
5710 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5712 // // loop on theElems
5713 // TIDSortedElemSet::iterator itElem;
5714 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5715 // const SMDS_MeshElement* elem = *itElem;
5719 // // loop on elem nodes
5720 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5721 // while ( itN->more() ) {
5723 // // check if a node has been already transformed
5724 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5725 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5726 // nodeMap.insert( make_pair ( node, node ));
5727 // if ( !n2n_isnew.second )
5730 // //double coord[3];
5731 // //coord[0] = node->X();
5732 // //coord[1] = node->Y();
5733 // //coord[2] = node->Z();
5734 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5735 // double dx = (node->X() - thePoint.X()) * scaleX;
5736 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5737 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5738 // if ( theTargetMesh ) {
5739 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5740 // const SMDS_MeshNode * newNode =
5741 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5742 // n2n_isnew.first->second = newNode;
5743 // myLastCreatedNodes.Append(newNode);
5744 // srcNodes.Append( node );
5746 // else if ( theCopy ) {
5747 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5748 // const SMDS_MeshNode * newNode =
5749 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5750 // n2n_isnew.first->second = newNode;
5751 // myLastCreatedNodes.Append(newNode);
5752 // srcNodes.Append( node );
5755 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5756 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5757 // // node position on shape becomes invalid
5758 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5759 // ( SMDS_SpacePosition::originSpacePosition() );
5762 // // keep inverse elements
5763 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5764 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5765 // // while ( invElemIt->more() ) {
5766 // // const SMDS_MeshElement* iel = invElemIt->next();
5767 // // inverseElemSet.insert( iel );
5773 // // either create new elements or reverse mirrored ones
5774 // //if ( !theCopy && !needReverse && !theTargetMesh )
5775 // if ( !theCopy && !theTargetMesh )
5776 // return PGroupIDs();
5778 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5779 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5780 // theElems.insert( *invElemIt );
5782 // // replicate or reverse elements
5785 // REV_TETRA = 0, // = nbNodes - 4
5786 // REV_PYRAMID = 1, // = nbNodes - 4
5787 // REV_PENTA = 2, // = nbNodes - 4
5789 // REV_HEXA = 4, // = nbNodes - 4
5792 // int index[][8] = {
5793 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5794 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5795 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5796 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5797 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5798 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5801 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5803 // const SMDS_MeshElement* elem = *itElem;
5804 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5807 // int nbNodes = elem->NbNodes();
5808 // int elemType = elem->GetType();
5810 // if (elem->IsPoly()) {
5811 // // Polygon or Polyhedral Volume
5812 // switch ( elemType ) {
5813 // case SMDSAbs_Face:
5815 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5817 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5818 // while (itN->more()) {
5819 // const SMDS_MeshNode* node =
5820 // static_cast<const SMDS_MeshNode*>(itN->next());
5821 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5822 // if (nodeMapIt == nodeMap.end())
5823 // break; // not all nodes transformed
5824 // //if (needReverse) {
5825 // // // reverse mirrored faces and volumes
5826 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5828 // poly_nodes[iNode] = (*nodeMapIt).second;
5832 // if ( iNode != nbNodes )
5833 // continue; // not all nodes transformed
5835 // if ( theTargetMesh ) {
5836 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5837 // srcElems.Append( elem );
5839 // else if ( theCopy ) {
5840 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5841 // srcElems.Append( elem );
5844 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5848 // case SMDSAbs_Volume:
5850 // // ATTENTION: Reversing is not yet done!!!
5851 // const SMDS_VtkVolume* aPolyedre =
5852 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5853 // if (!aPolyedre) {
5854 // MESSAGE("Warning: bad volumic element");
5858 // vector<const SMDS_MeshNode*> poly_nodes;
5859 // vector<int> quantities;
5861 // bool allTransformed = true;
5862 // int nbFaces = aPolyedre->NbFaces();
5863 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5864 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5865 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5866 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5867 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5868 // if (nodeMapIt == nodeMap.end()) {
5869 // allTransformed = false; // not all nodes transformed
5871 // poly_nodes.push_back((*nodeMapIt).second);
5874 // quantities.push_back(nbFaceNodes);
5876 // if ( !allTransformed )
5877 // continue; // not all nodes transformed
5879 // if ( theTargetMesh ) {
5880 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5881 // srcElems.Append( elem );
5883 // else if ( theCopy ) {
5884 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5885 // srcElems.Append( elem );
5888 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5897 // // Regular elements
5898 // int* i = index[ FORWARD ];
5899 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5900 // // if ( elemType == SMDSAbs_Face )
5901 // // i = index[ REV_FACE ];
5903 // // i = index[ nbNodes - 4 ];
5905 // if(elem->IsQuadratic()) {
5906 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5908 // //if(needReverse) {
5909 // // if(nbNodes==3) { // quadratic edge
5910 // // static int anIds[] = {1,0,2};
5913 // // else if(nbNodes==6) { // quadratic triangle
5914 // // static int anIds[] = {0,2,1,5,4,3};
5917 // // else if(nbNodes==8) { // quadratic quadrangle
5918 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5921 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5922 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5925 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5926 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5929 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5930 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5933 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5934 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5940 // // find transformed nodes
5941 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5943 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5944 // while ( itN->more() ) {
5945 // const SMDS_MeshNode* node =
5946 // static_cast<const SMDS_MeshNode*>( itN->next() );
5947 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5948 // if ( nodeMapIt == nodeMap.end() )
5949 // break; // not all nodes transformed
5950 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5952 // if ( iNode != nbNodes )
5953 // continue; // not all nodes transformed
5955 // if ( theTargetMesh ) {
5956 // if ( SMDS_MeshElement* copy =
5957 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5958 // myLastCreatedElems.Append( copy );
5959 // srcElems.Append( elem );
5962 // else if ( theCopy ) {
5963 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5964 // myLastCreatedElems.Append( copy );
5965 // srcElems.Append( elem );
5969 // // reverse element as it was reversed by transformation
5970 // if ( nbNodes > 2 )
5971 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5975 // PGroupIDs newGroupIDs;
5977 // if ( theMakeGroups && theCopy ||
5978 // theMakeGroups && theTargetMesh ) {
5979 // string groupPostfix = "scaled";
5980 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5983 // return newGroupIDs;
5987 //=======================================================================
5989 * \brief Create groups of elements made during transformation
5990 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5991 * \param elemGens - elements making corresponding myLastCreatedElems
5992 * \param postfix - to append to names of new groups
5994 //=======================================================================
5996 SMESH_MeshEditor::PGroupIDs
5997 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5998 const SMESH_SequenceOfElemPtr& elemGens,
5999 const std::string& postfix,
6000 SMESH_Mesh* targetMesh)
6002 PGroupIDs newGroupIDs( new list<int> );
6003 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6005 // Sort existing groups by types and collect their names
6007 // to store an old group and a generated new one
6008 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6009 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6011 set< string > groupNames;
6013 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6014 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6015 while ( groupIt->more() ) {
6016 SMESH_Group * group = groupIt->next();
6017 if ( !group ) continue;
6018 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6019 if ( !groupDS || groupDS->IsEmpty() ) continue;
6020 groupNames.insert( group->GetName() );
6021 groupDS->SetStoreName( group->GetName() );
6022 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6027 // loop on nodes and elements
6028 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6030 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6031 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6032 if ( gens.Length() != elems.Length() )
6033 throw SALOME_Exception(LOCALIZED("invalid args"));
6035 // loop on created elements
6036 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6038 const SMDS_MeshElement* sourceElem = gens( iElem );
6039 if ( !sourceElem ) {
6040 MESSAGE("generateGroups(): NULL source element");
6043 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6044 if ( groupsOldNew.empty() ) {
6045 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6046 ++iElem; // skip all elements made by sourceElem
6049 // collect all elements made by sourceElem
6050 list< const SMDS_MeshElement* > resultElems;
6051 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6052 if ( resElem != sourceElem )
6053 resultElems.push_back( resElem );
6054 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6055 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6056 if ( resElem != sourceElem )
6057 resultElems.push_back( resElem );
6058 // do not generate element groups from node ones
6059 if ( sourceElem->GetType() == SMDSAbs_Node &&
6060 elems( iElem )->GetType() != SMDSAbs_Node )
6063 // add resultElems to groups made by ones the sourceElem belongs to
6064 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6065 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6067 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6068 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6070 SMDS_MeshGroup* & newGroup = gOldNew->second;
6071 if ( !newGroup )// create a new group
6074 string name = oldGroup->GetStoreName();
6075 if ( !targetMesh ) {
6079 while ( !groupNames.insert( name ).second ) // name exists
6085 TCollection_AsciiString nbStr(nb+1);
6086 name.resize( name.rfind('_')+1 );
6087 name += nbStr.ToCString();
6094 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6096 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6097 newGroup = & groupDS->SMDSGroup();
6098 newGroupIDs->push_back( id );
6101 // fill in a new group
6102 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6103 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6104 newGroup->Add( *resElemIt );
6107 } // loop on created elements
6108 }// loop on nodes and elements
6113 //================================================================================
6115 * \brief Return list of group of nodes close to each other within theTolerance
6116 * Search among theNodes or in the whole mesh if theNodes is empty using
6117 * an Octree algorithm
6119 //================================================================================
6121 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6122 const double theTolerance,
6123 TListOfListOfNodes & theGroupsOfNodes)
6125 myLastCreatedElems.Clear();
6126 myLastCreatedNodes.Clear();
6128 if ( theNodes.empty() )
6129 { // get all nodes in the mesh
6130 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6131 while ( nIt->more() )
6132 theNodes.insert( theNodes.end(),nIt->next());
6135 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6139 //=======================================================================
6141 * \brief Implementation of search for the node closest to point
6143 //=======================================================================
6145 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6147 //---------------------------------------------------------------------
6149 * \brief Constructor
6151 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6153 myMesh = ( SMESHDS_Mesh* ) theMesh;
6155 TIDSortedNodeSet nodes;
6157 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6158 while ( nIt->more() )
6159 nodes.insert( nodes.end(), nIt->next() );
6161 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6163 // get max size of a leaf box
6164 SMESH_OctreeNode* tree = myOctreeNode;
6165 while ( !tree->isLeaf() )
6167 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6171 myHalfLeafSize = tree->maxSize() / 2.;
6174 //---------------------------------------------------------------------
6176 * \brief Move node and update myOctreeNode accordingly
6178 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6180 myOctreeNode->UpdateByMoveNode( node, toPnt );
6181 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6184 //---------------------------------------------------------------------
6186 * \brief Do it's job
6188 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6190 map<double, const SMDS_MeshNode*> dist2Nodes;
6191 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6192 if ( !dist2Nodes.empty() )
6193 return dist2Nodes.begin()->second;
6194 list<const SMDS_MeshNode*> nodes;
6195 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6197 double minSqDist = DBL_MAX;
6198 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6200 // sort leafs by their distance from thePnt
6201 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6202 TDistTreeMap treeMap;
6203 list< SMESH_OctreeNode* > treeList;
6204 list< SMESH_OctreeNode* >::iterator trIt;
6205 treeList.push_back( myOctreeNode );
6207 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6208 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6209 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6211 SMESH_OctreeNode* tree = *trIt;
6212 if ( !tree->isLeaf() ) // put children to the queue
6214 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6215 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6216 while ( cIt->more() )
6217 treeList.push_back( cIt->next() );
6219 else if ( tree->NbNodes() ) // put a tree to the treeMap
6221 const Bnd_B3d& box = tree->getBox();
6222 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6223 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6224 if ( !it_in.second ) // not unique distance to box center
6225 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6228 // find distance after which there is no sense to check tree's
6229 double sqLimit = DBL_MAX;
6230 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6231 if ( treeMap.size() > 5 ) {
6232 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6233 const Bnd_B3d& box = closestTree->getBox();
6234 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6235 sqLimit = limit * limit;
6237 // get all nodes from trees
6238 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6239 if ( sqDist_tree->first > sqLimit )
6241 SMESH_OctreeNode* tree = sqDist_tree->second;
6242 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6245 // find closest among nodes
6246 minSqDist = DBL_MAX;
6247 const SMDS_MeshNode* closestNode = 0;
6248 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6249 for ( ; nIt != nodes.end(); ++nIt ) {
6250 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6251 if ( minSqDist > sqDist ) {
6259 //---------------------------------------------------------------------
6263 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6265 //---------------------------------------------------------------------
6267 * \brief Return the node tree
6269 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6272 SMESH_OctreeNode* myOctreeNode;
6273 SMESHDS_Mesh* myMesh;
6274 double myHalfLeafSize; // max size of a leaf box
6277 //=======================================================================
6279 * \brief Return SMESH_NodeSearcher
6281 //=======================================================================
6283 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6285 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6288 // ========================================================================
6289 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6291 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6292 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6293 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6295 //=======================================================================
6297 * \brief Octal tree of bounding boxes of elements
6299 //=======================================================================
6301 class ElementBndBoxTree : public SMESH_Octree
6305 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6306 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6307 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6308 ~ElementBndBoxTree();
6311 ElementBndBoxTree() {}
6312 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6313 void buildChildrenData();
6314 Bnd_B3d* buildRootBox();
6316 //!< Bounding box of element
6317 struct ElementBox : public Bnd_B3d
6319 const SMDS_MeshElement* _element;
6320 int _refCount; // an ElementBox can be included in several tree branches
6321 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6323 vector< ElementBox* > _elements;
6326 //================================================================================
6328 * \brief ElementBndBoxTree creation
6330 //================================================================================
6332 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6333 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6335 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6336 _elements.reserve( nbElems );
6338 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6339 while ( elemIt->more() )
6340 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6342 if ( _elements.size() > MaxNbElemsInLeaf )
6348 //================================================================================
6352 //================================================================================
6354 ElementBndBoxTree::~ElementBndBoxTree()
6356 for ( int i = 0; i < _elements.size(); ++i )
6357 if ( --_elements[i]->_refCount <= 0 )
6358 delete _elements[i];
6361 //================================================================================
6363 * \brief Return the maximal box
6365 //================================================================================
6367 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6369 Bnd_B3d* box = new Bnd_B3d;
6370 for ( int i = 0; i < _elements.size(); ++i )
6371 box->Add( *_elements[i] );
6375 //================================================================================
6377 * \brief Redistrubute element boxes among children
6379 //================================================================================
6381 void ElementBndBoxTree::buildChildrenData()
6383 for ( int i = 0; i < _elements.size(); ++i )
6385 for (int j = 0; j < 8; j++)
6387 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6389 _elements[i]->_refCount++;
6390 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6393 _elements[i]->_refCount--;
6397 for (int j = 0; j < 8; j++)
6399 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6400 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6401 child->myIsLeaf = true;
6403 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6404 child->_elements.resize( child->_elements.size() ); // compact
6408 //================================================================================
6410 * \brief Return elements which can include the point
6412 //================================================================================
6414 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6415 TIDSortedElemSet& foundElems)
6417 if ( level() && getBox().IsOut( point.XYZ() ))
6422 for ( int i = 0; i < _elements.size(); ++i )
6423 if ( !_elements[i]->IsOut( point.XYZ() ))
6424 foundElems.insert( _elements[i]->_element );
6428 for (int i = 0; i < 8; i++)
6429 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6433 //================================================================================
6435 * \brief Return elements which can be intersected by the line
6437 //================================================================================
6439 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6440 TIDSortedElemSet& foundElems)
6442 if ( level() && getBox().IsOut( line ))
6447 for ( int i = 0; i < _elements.size(); ++i )
6448 if ( !_elements[i]->IsOut( line ))
6449 foundElems.insert( _elements[i]->_element );
6453 for (int i = 0; i < 8; i++)
6454 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6458 //================================================================================
6460 * \brief Construct the element box
6462 //================================================================================
6464 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6468 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6469 while ( nIt->more() )
6470 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6471 Enlarge( tolerance );
6476 //=======================================================================
6478 * \brief Implementation of search for the elements by point and
6479 * of classification of point in 2D mesh
6481 //=======================================================================
6483 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6485 SMESHDS_Mesh* _mesh;
6486 SMDS_ElemIteratorPtr _meshPartIt;
6487 ElementBndBoxTree* _ebbTree;
6488 SMESH_NodeSearcherImpl* _nodeSearcher;
6489 SMDSAbs_ElementType _elementType;
6491 bool _outerFacesFound;
6492 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6494 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6495 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6496 ~SMESH_ElementSearcherImpl()
6498 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6499 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6501 virtual int FindElementsByPoint(const gp_Pnt& point,
6502 SMDSAbs_ElementType type,
6503 vector< const SMDS_MeshElement* >& foundElements);
6504 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6506 void GetElementsNearLine( const gp_Ax1& line,
6507 SMDSAbs_ElementType type,
6508 vector< const SMDS_MeshElement* >& foundElems);
6509 double getTolerance();
6510 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6511 const double tolerance, double & param);
6512 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6513 bool isOuterBoundary(const SMDS_MeshElement* face) const
6515 return _outerFaces.empty() || _outerFaces.count(face);
6517 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6519 const SMDS_MeshElement* _face;
6521 bool _coincides; //!< the line lays in face plane
6522 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6523 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6525 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6528 TIDSortedElemSet _faces;
6529 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6530 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6534 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6536 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6537 << ", _coincides="<<i._coincides << ")";
6540 //=======================================================================
6542 * \brief define tolerance for search
6544 //=======================================================================
6546 double SMESH_ElementSearcherImpl::getTolerance()
6548 if ( _tolerance < 0 )
6550 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6553 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6555 double boxSize = _nodeSearcher->getTree()->maxSize();
6556 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6558 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6560 double boxSize = _ebbTree->maxSize();
6561 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6563 if ( _tolerance == 0 )
6565 // define tolerance by size of a most complex element
6566 int complexType = SMDSAbs_Volume;
6567 while ( complexType > SMDSAbs_All &&
6568 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6570 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6572 if ( complexType == int( SMDSAbs_Node ))
6574 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6576 if ( meshInfo.NbNodes() > 2 )
6577 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6581 SMDS_ElemIteratorPtr elemIt =
6582 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6583 const SMDS_MeshElement* elem = elemIt->next();
6584 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6585 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6587 while ( nodeIt->more() )
6589 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6590 elemSize = max( dist, elemSize );
6593 _tolerance = 1e-4 * elemSize;
6599 //================================================================================
6601 * \brief Find intersection of the line and an edge of face and return parameter on line
6603 //================================================================================
6605 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6606 const SMDS_MeshElement* face,
6613 GeomAPI_ExtremaCurveCurve anExtCC;
6614 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6616 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6617 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6619 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6620 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6621 anExtCC.Init( lineCurve, edge);
6622 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6624 Quantity_Parameter pl, pe;
6625 anExtCC.LowerDistanceParameters( pl, pe );
6627 if ( ++nbInts == 2 )
6631 if ( nbInts > 0 ) param /= nbInts;
6634 //================================================================================
6636 * \brief Find all faces belonging to the outer boundary of mesh
6638 //================================================================================
6640 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6642 if ( _outerFacesFound ) return;
6644 // Collect all outer faces by passing from one outer face to another via their links
6645 // and BTW find out if there are internal faces at all.
6647 // checked links and links where outer boundary meets internal one
6648 set< SMESH_TLink > visitedLinks, seamLinks;
6650 // links to treat with already visited faces sharing them
6651 list < TFaceLink > startLinks;
6653 // load startLinks with the first outerFace
6654 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6655 _outerFaces.insert( outerFace );
6657 TIDSortedElemSet emptySet;
6658 while ( !startLinks.empty() )
6660 const SMESH_TLink& link = startLinks.front()._link;
6661 TIDSortedElemSet& faces = startLinks.front()._faces;
6663 outerFace = *faces.begin();
6664 // find other faces sharing the link
6665 const SMDS_MeshElement* f;
6666 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6669 // select another outer face among the found
6670 const SMDS_MeshElement* outerFace2 = 0;
6671 if ( faces.size() == 2 )
6673 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6675 else if ( faces.size() > 2 )
6677 seamLinks.insert( link );
6679 // link direction within the outerFace
6680 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6681 SMESH_TNodeXYZ( link.node2()));
6682 int i1 = outerFace->GetNodeIndex( link.node1() );
6683 int i2 = outerFace->GetNodeIndex( link.node2() );
6684 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6685 if ( rev ) n1n2.Reverse();
6687 gp_XYZ ofNorm, fNorm;
6688 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6690 // direction from the link inside outerFace
6691 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6692 // sort all other faces by angle with the dirInOF
6693 map< double, const SMDS_MeshElement* > angle2Face;
6694 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6695 for ( ; face != faces.end(); ++face )
6697 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6699 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6700 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6701 if ( angle < 0 ) angle += 2*PI;
6702 angle2Face.insert( make_pair( angle, *face ));
6704 if ( !angle2Face.empty() )
6705 outerFace2 = angle2Face.begin()->second;
6708 // store the found outer face and add its links to continue seaching from
6711 _outerFaces.insert( outerFace );
6712 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6713 for ( int i = 0; i < nbNodes; ++i )
6715 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6716 if ( visitedLinks.insert( link2 ).second )
6717 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6720 startLinks.pop_front();
6722 _outerFacesFound = true;
6724 if ( !seamLinks.empty() )
6726 // There are internal boundaries touching the outher one,
6727 // find all faces of internal boundaries in order to find
6728 // faces of boundaries of holes, if any.
6733 _outerFaces.clear();
6737 //=======================================================================
6739 * \brief Find elements of given type where the given point is IN or ON.
6740 * Returns nb of found elements and elements them-selves.
6742 * 'ALL' type means elements of any type excluding nodes and 0D elements
6744 //=======================================================================
6746 int SMESH_ElementSearcherImpl::
6747 FindElementsByPoint(const gp_Pnt& point,
6748 SMDSAbs_ElementType type,
6749 vector< const SMDS_MeshElement* >& foundElements)
6751 foundElements.clear();
6753 double tolerance = getTolerance();
6755 // =================================================================================
6756 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6758 if ( !_nodeSearcher )
6759 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6761 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6762 if ( !closeNode ) return foundElements.size();
6764 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6765 return foundElements.size(); // to far from any node
6767 if ( type == SMDSAbs_Node )
6769 foundElements.push_back( closeNode );
6773 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6774 while ( elemIt->more() )
6775 foundElements.push_back( elemIt->next() );
6778 // =================================================================================
6779 else // elements more complex than 0D
6781 if ( !_ebbTree || _elementType != type )
6783 if ( _ebbTree ) delete _ebbTree;
6784 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6786 TIDSortedElemSet suspectElems;
6787 _ebbTree->getElementsNearPoint( point, suspectElems );
6788 TIDSortedElemSet::iterator elem = suspectElems.begin();
6789 for ( ; elem != suspectElems.end(); ++elem )
6790 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6791 foundElements.push_back( *elem );
6793 return foundElements.size();
6796 //================================================================================
6798 * \brief Classify the given point in the closed 2D mesh
6800 //================================================================================
6802 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6804 double tolerance = getTolerance();
6805 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6807 if ( _ebbTree ) delete _ebbTree;
6808 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6810 // Algo: analyse transition of a line starting at the point through mesh boundary;
6811 // try three lines parallel to axis of the coordinate system and perform rough
6812 // analysis. If solution is not clear perform thorough analysis.
6814 const int nbAxes = 3;
6815 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6816 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6817 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6818 multimap< int, int > nbInt2Axis; // to find the simplest case
6819 for ( int axis = 0; axis < nbAxes; ++axis )
6821 gp_Ax1 lineAxis( point, axisDir[axis]);
6822 gp_Lin line ( lineAxis );
6824 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6825 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6827 // Intersect faces with the line
6829 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6830 TIDSortedElemSet::iterator face = suspectFaces.begin();
6831 for ( ; face != suspectFaces.end(); ++face )
6835 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6836 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6838 // perform intersection
6839 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6840 if ( !intersection.IsDone() )
6842 if ( intersection.IsInQuadric() )
6844 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6846 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6848 gp_Pnt intersectionPoint = intersection.Point(1);
6849 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6850 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6853 // Analyse intersections roughly
6855 int nbInter = u2inters.size();
6859 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6860 if ( nbInter == 1 ) // not closed mesh
6861 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6863 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6866 if ( (f<0) == (l<0) )
6869 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6870 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6871 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6874 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6876 if ( _outerFacesFound ) break; // pass to thorough analysis
6878 } // three attempts - loop on CS axes
6880 // Analyse intersections thoroughly.
6881 // We make two loops maximum, on the first one we only exclude touching intersections,
6882 // on the second, if situation is still unclear, we gather and use information on
6883 // position of faces (internal or outer). If faces position is already gathered,
6884 // we make the second loop right away.
6886 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6888 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6889 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6891 int axis = nb_axis->second;
6892 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6894 gp_Ax1 lineAxis( point, axisDir[axis]);
6895 gp_Lin line ( lineAxis );
6897 // add tangent intersections to u2inters
6899 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6900 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6901 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6902 u2inters.insert(make_pair( param, *tgtInt ));
6903 tangentInters[ axis ].clear();
6905 // Count intersections before and after the point excluding touching ones.
6906 // If hasPositionInfo we count intersections of outer boundary only
6908 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6909 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6910 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6911 bool ok = ! u_int1->second._coincides;
6912 while ( ok && u_int1 != u2inters.end() )
6914 double u = u_int1->first;
6915 bool touchingInt = false;
6916 if ( ++u_int2 != u2inters.end() )
6918 // skip intersections at the same point (if the line passes through edge or node)
6920 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6926 // skip tangent intersections
6928 const SMDS_MeshElement* prevFace = u_int1->second._face;
6929 while ( ok && u_int2->second._coincides )
6931 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6937 ok = ( u_int2 != u2inters.end() );
6942 // skip intersections at the same point after tangent intersections
6945 double u2 = u_int2->first;
6947 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6953 // decide if we skipped a touching intersection
6954 if ( nbSamePnt + nbTgt > 0 )
6956 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6957 map< double, TInters >::iterator u_int = u_int1;
6958 for ( ; u_int != u_int2; ++u_int )
6960 if ( u_int->second._coincides ) continue;
6961 double dot = u_int->second._faceNorm * line.Direction();
6962 if ( dot > maxDot ) maxDot = dot;
6963 if ( dot < minDot ) minDot = dot;
6965 touchingInt = ( minDot*maxDot < 0 );
6970 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6981 u_int1 = u_int2; // to next intersection
6983 } // loop on intersections with one line
6987 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6990 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6993 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6994 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6996 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6999 if ( (f<0) == (l<0) )
7002 if ( hasPositionInfo )
7003 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7005 } // loop on intersections of the tree lines - thorough analysis
7007 if ( !hasPositionInfo )
7009 // gather info on faces position - is face in the outer boundary or not
7010 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7011 findOuterBoundary( u2inters.begin()->second._face );
7014 } // two attempts - with and w/o faces position info in the mesh
7016 return TopAbs_UNKNOWN;
7019 //=======================================================================
7021 * \brief Return elements possibly intersecting the line
7023 //=======================================================================
7025 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7026 SMDSAbs_ElementType type,
7027 vector< const SMDS_MeshElement* >& foundElems)
7029 if ( !_ebbTree || _elementType != type )
7031 if ( _ebbTree ) delete _ebbTree;
7032 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7034 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7035 _ebbTree->getElementsNearLine( line, suspectFaces );
7036 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7039 //=======================================================================
7041 * \brief Return SMESH_ElementSearcher
7043 //=======================================================================
7045 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7047 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7050 //=======================================================================
7052 * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7054 //=======================================================================
7056 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7058 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7061 //=======================================================================
7063 * \brief Return true if the point is IN or ON of the element
7065 //=======================================================================
7067 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7069 if ( element->GetType() == SMDSAbs_Volume)
7071 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7074 // get ordered nodes
7076 vector< gp_XYZ > xyz;
7077 vector<const SMDS_MeshNode*> nodeList;
7079 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7080 if ( element->IsQuadratic() ) {
7081 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7082 nodeIt = f->interlacedNodesElemIterator();
7083 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7084 nodeIt = e->interlacedNodesElemIterator();
7086 while ( nodeIt->more() )
7088 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7089 xyz.push_back( SMESH_TNodeXYZ(node) );
7090 nodeList.push_back(node);
7093 int i, nbNodes = element->NbNodes();
7095 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7097 // compute face normal
7098 gp_Vec faceNorm(0,0,0);
7099 xyz.push_back( xyz.front() );
7100 nodeList.push_back( nodeList.front() );
7101 for ( i = 0; i < nbNodes; ++i )
7103 gp_Vec edge1( xyz[i+1], xyz[i]);
7104 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7105 faceNorm += edge1 ^ edge2;
7107 double normSize = faceNorm.Magnitude();
7108 if ( normSize <= tol )
7110 // degenerated face: point is out if it is out of all face edges
7111 for ( i = 0; i < nbNodes; ++i )
7113 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7114 if ( !isOut( &edge, point, tol ))
7119 faceNorm /= normSize;
7121 // check if the point lays on face plane
7122 gp_Vec n2p( xyz[0], point );
7123 if ( fabs( n2p * faceNorm ) > tol )
7124 return true; // not on face plane
7126 // check if point is out of face boundary:
7127 // define it by closest transition of a ray point->infinity through face boundary
7128 // on the face plane.
7129 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7130 // to find intersections of the ray with the boundary.
7132 gp_Vec plnNorm = ray ^ faceNorm;
7133 normSize = plnNorm.Magnitude();
7134 if ( normSize <= tol ) return false; // point coincides with the first node
7135 plnNorm /= normSize;
7136 // for each node of the face, compute its signed distance to the plane
7137 vector<double> dist( nbNodes + 1);
7138 for ( i = 0; i < nbNodes; ++i )
7140 gp_Vec n2p( xyz[i], point );
7141 dist[i] = n2p * plnNorm;
7143 dist.back() = dist.front();
7144 // find the closest intersection
7146 double rClosest, distClosest = 1e100;;
7148 for ( i = 0; i < nbNodes; ++i )
7151 if ( fabs( dist[i]) < tol )
7153 else if ( fabs( dist[i+1]) < tol )
7155 else if ( dist[i] * dist[i+1] < 0 )
7156 r = dist[i] / ( dist[i] - dist[i+1] );
7158 continue; // no intersection
7159 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7160 gp_Vec p2int ( point, pInt);
7161 if ( p2int * ray > -tol ) // right half-space
7163 double intDist = p2int.SquareMagnitude();
7164 if ( intDist < distClosest )
7169 distClosest = intDist;
7174 return true; // no intesections - out
7176 // analyse transition
7177 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7178 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7179 gp_Vec p2int ( point, pClosest );
7180 bool out = (edgeNorm * p2int) < -tol;
7181 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7184 // ray pass through a face node; analyze transition through an adjacent edge
7185 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7186 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7187 gp_Vec edgeAdjacent( p1, p2 );
7188 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7189 bool out2 = (edgeNorm2 * p2int) < -tol;
7191 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7192 return covexCorner ? (out || out2) : (out && out2);
7194 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7196 // point is out of edge if it is NOT ON any straight part of edge
7197 // (we consider quadratic edge as being composed of two straight parts)
7198 for ( i = 1; i < nbNodes; ++i )
7200 gp_Vec edge( xyz[i-1], xyz[i]);
7201 gp_Vec n1p ( xyz[i-1], point);
7202 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7205 gp_Vec n2p( xyz[i], point );
7206 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7208 return false; // point is ON this part
7212 // Node or 0D element -------------------------------------------------------------------------
7214 gp_Vec n2p ( xyz[0], point );
7215 return n2p.Magnitude() <= tol;
7220 //=======================================================================
7221 //function : SimplifyFace
7223 //=======================================================================
7224 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7225 vector<const SMDS_MeshNode *>& poly_nodes,
7226 vector<int>& quantities) const
7228 int nbNodes = faceNodes.size();
7233 set<const SMDS_MeshNode*> nodeSet;
7235 // get simple seq of nodes
7236 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7237 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7238 int iSimple = 0, nbUnique = 0;
7240 simpleNodes[iSimple++] = faceNodes[0];
7242 for (int iCur = 1; iCur < nbNodes; iCur++) {
7243 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7244 simpleNodes[iSimple++] = faceNodes[iCur];
7245 if (nodeSet.insert( faceNodes[iCur] ).second)
7249 int nbSimple = iSimple;
7250 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7260 bool foundLoop = (nbSimple > nbUnique);
7263 set<const SMDS_MeshNode*> loopSet;
7264 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7265 const SMDS_MeshNode* n = simpleNodes[iSimple];
7266 if (!loopSet.insert( n ).second) {
7270 int iC = 0, curLast = iSimple;
7271 for (; iC < curLast; iC++) {
7272 if (simpleNodes[iC] == n) break;
7274 int loopLen = curLast - iC;
7276 // create sub-element
7278 quantities.push_back(loopLen);
7279 for (; iC < curLast; iC++) {
7280 poly_nodes.push_back(simpleNodes[iC]);
7283 // shift the rest nodes (place from the first loop position)
7284 for (iC = curLast + 1; iC < nbSimple; iC++) {
7285 simpleNodes[iC - loopLen] = simpleNodes[iC];
7287 nbSimple -= loopLen;
7290 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7291 } // while (foundLoop)
7295 quantities.push_back(iSimple);
7296 for (int i = 0; i < iSimple; i++)
7297 poly_nodes.push_back(simpleNodes[i]);
7303 //=======================================================================
7304 //function : MergeNodes
7305 //purpose : In each group, the cdr of nodes are substituted by the first one
7307 //=======================================================================
7309 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7311 MESSAGE("MergeNodes");
7312 myLastCreatedElems.Clear();
7313 myLastCreatedNodes.Clear();
7315 SMESHDS_Mesh* aMesh = GetMeshDS();
7317 TNodeNodeMap nodeNodeMap; // node to replace - new node
7318 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7319 list< int > rmElemIds, rmNodeIds;
7321 // Fill nodeNodeMap and elems
7323 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7324 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7325 list<const SMDS_MeshNode*>& nodes = *grIt;
7326 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7327 const SMDS_MeshNode* nToKeep = *nIt;
7328 //MESSAGE("node to keep " << nToKeep->GetID());
7329 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7330 const SMDS_MeshNode* nToRemove = *nIt;
7331 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7332 if ( nToRemove != nToKeep ) {
7333 //MESSAGE(" node to remove " << nToRemove->GetID());
7334 rmNodeIds.push_back( nToRemove->GetID() );
7335 AddToSameGroups( nToKeep, nToRemove, aMesh );
7338 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7339 while ( invElemIt->more() ) {
7340 const SMDS_MeshElement* elem = invElemIt->next();
7345 // Change element nodes or remove an element
7347 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7348 for ( ; eIt != elems.end(); eIt++ ) {
7349 const SMDS_MeshElement* elem = *eIt;
7350 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7351 int nbNodes = elem->NbNodes();
7352 int aShapeId = FindShape( elem );
7354 set<const SMDS_MeshNode*> nodeSet;
7355 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7356 int iUnique = 0, iCur = 0, nbRepl = 0;
7357 vector<int> iRepl( nbNodes );
7359 // get new seq of nodes
7360 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7361 while ( itN->more() ) {
7362 const SMDS_MeshNode* n =
7363 static_cast<const SMDS_MeshNode*>( itN->next() );
7365 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7366 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7368 // BUG 0020185: begin
7370 bool stopRecur = false;
7371 set<const SMDS_MeshNode*> nodesRecur;
7372 nodesRecur.insert(n);
7373 while (!stopRecur) {
7374 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7375 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7376 n = (*nnIt_i).second;
7377 if (!nodesRecur.insert(n).second) {
7378 // error: recursive dependancy
7387 iRepl[ nbRepl++ ] = iCur;
7389 curNodes[ iCur ] = n;
7390 bool isUnique = nodeSet.insert( n ).second;
7392 uniqueNodes[ iUnique++ ] = n;
7393 if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7394 --nbRepl; // n do not stick to a node of the elem
7399 // Analyse element topology after replacement
7402 int nbUniqueNodes = nodeSet.size();
7403 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7404 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7405 // Polygons and Polyhedral volumes
7406 if (elem->IsPoly()) {
7408 if (elem->GetType() == SMDSAbs_Face) {
7410 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7412 for (; inode < nbNodes; inode++) {
7413 face_nodes[inode] = curNodes[inode];
7416 vector<const SMDS_MeshNode *> polygons_nodes;
7417 vector<int> quantities;
7418 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7421 for (int iface = 0; iface < nbNew; iface++) {
7422 int nbNodes = quantities[iface];
7423 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7424 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7425 poly_nodes[ii] = polygons_nodes[inode];
7427 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7428 myLastCreatedElems.Append(newElem);
7430 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7433 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7434 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7435 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7437 if (nbNew > 0) quid = nbNew - 1;
7438 vector<int> newquant(quantities.begin()+quid, quantities.end());
7439 const SMDS_MeshElement* newElem = 0;
7440 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7441 myLastCreatedElems.Append(newElem);
7442 if ( aShapeId && newElem )
7443 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7444 rmElemIds.push_back(elem->GetID());
7447 rmElemIds.push_back(elem->GetID());
7451 else if (elem->GetType() == SMDSAbs_Volume) {
7452 // Polyhedral volume
7453 if (nbUniqueNodes < 4) {
7454 rmElemIds.push_back(elem->GetID());
7457 // each face has to be analyzed in order to check volume validity
7458 const SMDS_VtkVolume* aPolyedre =
7459 dynamic_cast<const SMDS_VtkVolume*>( elem );
7461 int nbFaces = aPolyedre->NbFaces();
7463 vector<const SMDS_MeshNode *> poly_nodes;
7464 vector<int> quantities;
7466 for (int iface = 1; iface <= nbFaces; iface++) {
7467 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7468 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7470 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7471 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7472 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7473 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7474 faceNode = (*nnIt).second;
7476 faceNodes[inode - 1] = faceNode;
7479 SimplifyFace(faceNodes, poly_nodes, quantities);
7482 if (quantities.size() > 3) {
7483 // to be done: remove coincident faces
7486 if (quantities.size() > 3)
7488 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7489 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7490 const SMDS_MeshElement* newElem = 0;
7491 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7492 myLastCreatedElems.Append(newElem);
7493 if ( aShapeId && newElem )
7494 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7495 rmElemIds.push_back(elem->GetID());
7499 rmElemIds.push_back(elem->GetID());
7510 // TODO not all the possible cases are solved. Find something more generic?
7511 switch ( nbNodes ) {
7512 case 2: ///////////////////////////////////// EDGE
7513 isOk = false; break;
7514 case 3: ///////////////////////////////////// TRIANGLE
7515 isOk = false; break;
7517 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7519 else { //////////////////////////////////// QUADRANGLE
7520 if ( nbUniqueNodes < 3 )
7522 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7523 isOk = false; // opposite nodes stick
7524 //MESSAGE("isOk " << isOk);
7527 case 6: ///////////////////////////////////// PENTAHEDRON
7528 if ( nbUniqueNodes == 4 ) {
7529 // ---------------------------------> tetrahedron
7531 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7532 // all top nodes stick: reverse a bottom
7533 uniqueNodes[ 0 ] = curNodes [ 1 ];
7534 uniqueNodes[ 1 ] = curNodes [ 0 ];
7536 else if (nbRepl == 3 &&
7537 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7538 // all bottom nodes stick: set a top before
7539 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7540 uniqueNodes[ 0 ] = curNodes [ 3 ];
7541 uniqueNodes[ 1 ] = curNodes [ 4 ];
7542 uniqueNodes[ 2 ] = curNodes [ 5 ];
7544 else if (nbRepl == 4 &&
7545 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7546 // a lateral face turns into a line: reverse a bottom
7547 uniqueNodes[ 0 ] = curNodes [ 1 ];
7548 uniqueNodes[ 1 ] = curNodes [ 0 ];
7553 else if ( nbUniqueNodes == 5 ) {
7554 // PENTAHEDRON --------------------> 2 tetrahedrons
7555 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7556 // a bottom node sticks with a linked top one
7558 SMDS_MeshElement* newElem =
7559 aMesh->AddVolume(curNodes[ 3 ],
7562 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7563 myLastCreatedElems.Append(newElem);
7565 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7566 // 2. : reverse a bottom
7567 uniqueNodes[ 0 ] = curNodes [ 1 ];
7568 uniqueNodes[ 1 ] = curNodes [ 0 ];
7578 if(elem->IsQuadratic()) { // Quadratic quadrangle
7590 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7593 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7595 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7596 uniqueNodes[0] = curNodes[0];
7597 uniqueNodes[1] = curNodes[2];
7598 uniqueNodes[2] = curNodes[3];
7599 uniqueNodes[3] = curNodes[5];
7600 uniqueNodes[4] = curNodes[6];
7601 uniqueNodes[5] = curNodes[7];
7604 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7605 uniqueNodes[0] = curNodes[0];
7606 uniqueNodes[1] = curNodes[1];
7607 uniqueNodes[2] = curNodes[2];
7608 uniqueNodes[3] = curNodes[4];
7609 uniqueNodes[4] = curNodes[5];
7610 uniqueNodes[5] = curNodes[6];
7613 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7614 uniqueNodes[0] = curNodes[1];
7615 uniqueNodes[1] = curNodes[2];
7616 uniqueNodes[2] = curNodes[3];
7617 uniqueNodes[3] = curNodes[5];
7618 uniqueNodes[4] = curNodes[6];
7619 uniqueNodes[5] = curNodes[0];
7622 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7623 uniqueNodes[0] = curNodes[0];
7624 uniqueNodes[1] = curNodes[1];
7625 uniqueNodes[2] = curNodes[3];
7626 uniqueNodes[3] = curNodes[4];
7627 uniqueNodes[4] = curNodes[6];
7628 uniqueNodes[5] = curNodes[7];
7631 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7632 uniqueNodes[0] = curNodes[0];
7633 uniqueNodes[1] = curNodes[2];
7634 uniqueNodes[2] = curNodes[3];
7635 uniqueNodes[3] = curNodes[1];
7636 uniqueNodes[4] = curNodes[6];
7637 uniqueNodes[5] = curNodes[7];
7640 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7641 uniqueNodes[0] = curNodes[0];
7642 uniqueNodes[1] = curNodes[1];
7643 uniqueNodes[2] = curNodes[2];
7644 uniqueNodes[3] = curNodes[4];
7645 uniqueNodes[4] = curNodes[5];
7646 uniqueNodes[5] = curNodes[7];
7649 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7650 uniqueNodes[0] = curNodes[0];
7651 uniqueNodes[1] = curNodes[1];
7652 uniqueNodes[2] = curNodes[3];
7653 uniqueNodes[3] = curNodes[4];
7654 uniqueNodes[4] = curNodes[2];
7655 uniqueNodes[5] = curNodes[7];
7658 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7659 uniqueNodes[0] = curNodes[0];
7660 uniqueNodes[1] = curNodes[1];
7661 uniqueNodes[2] = curNodes[2];
7662 uniqueNodes[3] = curNodes[4];
7663 uniqueNodes[4] = curNodes[5];
7664 uniqueNodes[5] = curNodes[3];
7669 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7672 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7676 //////////////////////////////////// HEXAHEDRON
7678 SMDS_VolumeTool hexa (elem);
7679 hexa.SetExternalNormal();
7680 if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7681 //////////////////////// HEX ---> 1 tetrahedron
7682 for ( int iFace = 0; iFace < 6; iFace++ ) {
7683 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7684 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7685 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7686 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7687 // one face turns into a point ...
7688 int iOppFace = hexa.GetOppFaceIndex( iFace );
7689 ind = hexa.GetFaceNodesIndices( iOppFace );
7691 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7692 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7695 if ( nbStick == 1 ) {
7696 // ... and the opposite one - into a triangle.
7698 ind = hexa.GetFaceNodesIndices( iFace );
7699 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7706 else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7707 //////////////////////// HEX ---> 1 prism
7708 int nbTria = 0, iTria[3];
7709 const int *ind; // indices of face nodes
7710 // look for triangular faces
7711 for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7712 ind = hexa.GetFaceNodesIndices( iFace );
7713 TIDSortedNodeSet faceNodes;
7714 for ( iCur = 0; iCur < 4; iCur++ )
7715 faceNodes.insert( curNodes[ind[iCur]] );
7716 if ( faceNodes.size() == 3 )
7717 iTria[ nbTria++ ] = iFace;
7719 // check if triangles are opposite
7720 if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7723 // set nodes of the bottom triangle
7724 ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7726 for ( iCur = 0; iCur < 4; iCur++ )
7727 if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7728 indB.push_back( ind[iCur] );
7729 if ( !hexa.IsForward() )
7730 std::swap( indB[0], indB[2] );
7731 for ( iCur = 0; iCur < 3; iCur++ )
7732 uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7733 // set nodes of the top triangle
7734 const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7735 for ( iCur = 0; iCur < 3; ++iCur )
7736 for ( int j = 0; j < 4; ++j )
7737 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7739 uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7745 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7746 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7747 for ( int iFace = 0; iFace < 6; iFace++ ) {
7748 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7749 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7750 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7751 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7752 // one face turns into a point ...
7753 int iOppFace = hexa.GetOppFaceIndex( iFace );
7754 ind = hexa.GetFaceNodesIndices( iOppFace );
7756 iUnique = 2; // reverse a tetrahedron 1 bottom
7757 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7758 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7760 else if ( iUnique >= 0 )
7761 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7763 if ( nbStick == 0 ) {
7764 // ... and the opposite one is a quadrangle
7766 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7767 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7770 SMDS_MeshElement* newElem =
7771 aMesh->AddVolume(curNodes[ind[ 0 ]],
7774 curNodes[indTop[ 0 ]]);
7775 myLastCreatedElems.Append(newElem);
7777 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7784 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7785 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7786 // find indices of quad and tri faces
7787 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7788 for ( iFace = 0; iFace < 6; iFace++ ) {
7789 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7791 for ( iCur = 0; iCur < 4; iCur++ )
7792 nodeSet.insert( curNodes[ind[ iCur ]] );
7793 nbUniqueNodes = nodeSet.size();
7794 if ( nbUniqueNodes == 3 )
7795 iTriFace[ nbTri++ ] = iFace;
7796 else if ( nbUniqueNodes == 4 )
7797 iQuadFace[ nbQuad++ ] = iFace;
7799 if (nbQuad == 2 && nbTri == 4 &&
7800 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7801 // 2 opposite quadrangles stuck with a diagonal;
7802 // sample groups of merged indices: (0-4)(2-6)
7803 // --------------------------------------------> 2 tetrahedrons
7804 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7805 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7806 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7807 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7808 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7809 // stuck with 0-2 diagonal
7817 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7818 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7819 // stuck with 1-3 diagonal
7831 uniqueNodes[ 0 ] = curNodes [ i0 ];
7832 uniqueNodes[ 1 ] = curNodes [ i1d ];
7833 uniqueNodes[ 2 ] = curNodes [ i3d ];
7834 uniqueNodes[ 3 ] = curNodes [ i0t ];
7837 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7841 myLastCreatedElems.Append(newElem);
7843 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7846 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7847 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7848 // --------------------------------------------> prism
7849 // find 2 opposite triangles
7851 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7852 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7853 // find indices of kept and replaced nodes
7854 // and fill unique nodes of 2 opposite triangles
7855 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7856 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7857 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7858 // fill unique nodes
7861 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7862 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7863 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7865 // iCur of a linked node of the opposite face (make normals co-directed):
7866 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7867 // check that correspondent corners of triangles are linked
7868 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7871 uniqueNodes[ iUnique ] = n;
7872 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7881 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7884 MESSAGE("MergeNodes() removes hexahedron "<< elem);
7891 } // switch ( nbNodes )
7893 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7895 if ( isOk ) { // the elem remains valid after sticking nodes
7896 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7898 // Change nodes of polyedre
7899 const SMDS_VtkVolume* aPolyedre =
7900 dynamic_cast<const SMDS_VtkVolume*>( elem );
7902 int nbFaces = aPolyedre->NbFaces();
7904 vector<const SMDS_MeshNode *> poly_nodes;
7905 vector<int> quantities (nbFaces);
7907 for (int iface = 1; iface <= nbFaces; iface++) {
7908 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7909 quantities[iface - 1] = nbFaceNodes;
7911 for (inode = 1; inode <= nbFaceNodes; inode++) {
7912 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7914 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7915 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7916 curNode = (*nnIt).second;
7918 poly_nodes.push_back(curNode);
7921 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7924 else // replace non-polyhedron elements
7926 const SMDSAbs_ElementType etyp = elem->GetType();
7927 const int elemId = elem->GetID();
7928 const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
7929 uniqueNodes.resize(nbUniqueNodes);
7931 SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7933 aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7934 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7935 if ( sm && newElem )
7936 sm->AddElement( newElem );
7937 if ( elem != newElem )
7938 ReplaceElemInGroups( elem, newElem, aMesh );
7942 // Remove invalid regular element or invalid polygon
7943 rmElemIds.push_back( elem->GetID() );
7946 } // loop on elements
7948 // Remove bad elements, then equal nodes (order important)
7950 Remove( rmElemIds, false );
7951 Remove( rmNodeIds, true );
7956 // ========================================================
7957 // class : SortableElement
7958 // purpose : allow sorting elements basing on their nodes
7959 // ========================================================
7960 class SortableElement : public set <const SMDS_MeshElement*>
7964 SortableElement( const SMDS_MeshElement* theElem )
7967 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7968 while ( nodeIt->more() )
7969 this->insert( nodeIt->next() );
7972 const SMDS_MeshElement* Get() const
7975 void Set(const SMDS_MeshElement* e) const
7980 mutable const SMDS_MeshElement* myElem;
7983 //=======================================================================
7984 //function : FindEqualElements
7985 //purpose : Return list of group of elements built on the same nodes.
7986 // Search among theElements or in the whole mesh if theElements is empty
7987 //=======================================================================
7988 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7989 TListOfListOfElementsID & theGroupsOfElementsID)
7991 myLastCreatedElems.Clear();
7992 myLastCreatedNodes.Clear();
7994 typedef set<const SMDS_MeshElement*> TElemsSet;
7995 typedef map< SortableElement, int > TMapOfNodeSet;
7996 typedef list<int> TGroupOfElems;
7999 if ( theElements.empty() )
8000 { // get all elements in the mesh
8001 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8002 while ( eIt->more() )
8003 elems.insert( elems.end(), eIt->next());
8006 elems = theElements;
8008 vector< TGroupOfElems > arrayOfGroups;
8009 TGroupOfElems groupOfElems;
8010 TMapOfNodeSet mapOfNodeSet;
8012 TElemsSet::iterator elemIt = elems.begin();
8013 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8014 const SMDS_MeshElement* curElem = *elemIt;
8015 SortableElement SE(curElem);
8018 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8019 if( !(pp.second) ) {
8020 TMapOfNodeSet::iterator& itSE = pp.first;
8021 ind = (*itSE).second;
8022 arrayOfGroups[ind].push_back(curElem->GetID());
8025 groupOfElems.clear();
8026 groupOfElems.push_back(curElem->GetID());
8027 arrayOfGroups.push_back(groupOfElems);
8032 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8033 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8034 groupOfElems = *groupIt;
8035 if ( groupOfElems.size() > 1 ) {
8036 groupOfElems.sort();
8037 theGroupsOfElementsID.push_back(groupOfElems);
8042 //=======================================================================
8043 //function : MergeElements
8044 //purpose : In each given group, substitute all elements by the first one.
8045 //=======================================================================
8047 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8049 myLastCreatedElems.Clear();
8050 myLastCreatedNodes.Clear();
8052 typedef list<int> TListOfIDs;
8053 TListOfIDs rmElemIds; // IDs of elems to remove
8055 SMESHDS_Mesh* aMesh = GetMeshDS();
8057 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8058 while ( groupsIt != theGroupsOfElementsID.end() ) {
8059 TListOfIDs& aGroupOfElemID = *groupsIt;
8060 aGroupOfElemID.sort();
8061 int elemIDToKeep = aGroupOfElemID.front();
8062 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8063 aGroupOfElemID.pop_front();
8064 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8065 while ( idIt != aGroupOfElemID.end() ) {
8066 int elemIDToRemove = *idIt;
8067 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8068 // add the kept element in groups of removed one (PAL15188)
8069 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8070 rmElemIds.push_back( elemIDToRemove );
8076 Remove( rmElemIds, false );
8079 //=======================================================================
8080 //function : MergeEqualElements
8081 //purpose : Remove all but one of elements built on the same nodes.
8082 //=======================================================================
8084 void SMESH_MeshEditor::MergeEqualElements()
8086 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8087 to merge equal elements in the whole mesh */
8088 TListOfListOfElementsID aGroupsOfElementsID;
8089 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8090 MergeElements(aGroupsOfElementsID);
8093 //=======================================================================
8094 //function : FindFaceInSet
8095 //purpose : Return a face having linked nodes n1 and n2 and which is
8096 // - not in avoidSet,
8097 // - in elemSet provided that !elemSet.empty()
8098 // i1 and i2 optionally returns indices of n1 and n2
8099 //=======================================================================
8101 const SMDS_MeshElement*
8102 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8103 const SMDS_MeshNode* n2,
8104 const TIDSortedElemSet& elemSet,
8105 const TIDSortedElemSet& avoidSet,
8111 const SMDS_MeshElement* face = 0;
8113 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8114 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8115 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8117 //MESSAGE("in while ( invElemIt->more() && !face )");
8118 const SMDS_MeshElement* elem = invElemIt->next();
8119 if (avoidSet.count( elem ))
8121 if ( !elemSet.empty() && !elemSet.count( elem ))
8124 i1 = elem->GetNodeIndex( n1 );
8125 // find a n2 linked to n1
8126 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8127 for ( int di = -1; di < 2 && !face; di += 2 )
8129 i2 = (i1+di+nbN) % nbN;
8130 if ( elem->GetNode( i2 ) == n2 )
8133 if ( !face && elem->IsQuadratic())
8135 // analysis for quadratic elements using all nodes
8136 const SMDS_VtkFace* F =
8137 dynamic_cast<const SMDS_VtkFace*>(elem);
8138 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8139 // use special nodes iterator
8140 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8141 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8142 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8144 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8145 if ( n1 == prevN && n2 == n )
8149 else if ( n2 == prevN && n1 == n )
8151 face = elem; swap( i1, i2 );
8157 if ( n1ind ) *n1ind = i1;
8158 if ( n2ind ) *n2ind = i2;
8162 //=======================================================================
8163 //function : findAdjacentFace
8165 //=======================================================================
8167 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8168 const SMDS_MeshNode* n2,
8169 const SMDS_MeshElement* elem)
8171 TIDSortedElemSet elemSet, avoidSet;
8173 avoidSet.insert ( elem );
8174 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8177 //=======================================================================
8178 //function : FindFreeBorder
8180 //=======================================================================
8182 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8184 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8185 const SMDS_MeshNode* theSecondNode,
8186 const SMDS_MeshNode* theLastNode,
8187 list< const SMDS_MeshNode* > & theNodes,
8188 list< const SMDS_MeshElement* >& theFaces)
8190 if ( !theFirstNode || !theSecondNode )
8192 // find border face between theFirstNode and theSecondNode
8193 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8197 theFaces.push_back( curElem );
8198 theNodes.push_back( theFirstNode );
8199 theNodes.push_back( theSecondNode );
8201 //vector<const SMDS_MeshNode*> nodes;
8202 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8203 TIDSortedElemSet foundElems;
8204 bool needTheLast = ( theLastNode != 0 );
8206 while ( nStart != theLastNode ) {
8207 if ( nStart == theFirstNode )
8208 return !needTheLast;
8210 // find all free border faces sharing form nStart
8212 list< const SMDS_MeshElement* > curElemList;
8213 list< const SMDS_MeshNode* > nStartList;
8214 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8215 while ( invElemIt->more() ) {
8216 const SMDS_MeshElement* e = invElemIt->next();
8217 if ( e == curElem || foundElems.insert( e ).second ) {
8219 int iNode = 0, nbNodes = e->NbNodes();
8220 //const SMDS_MeshNode* nodes[nbNodes+1];
8221 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8223 if(e->IsQuadratic()) {
8224 const SMDS_VtkFace* F =
8225 dynamic_cast<const SMDS_VtkFace*>(e);
8226 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8227 // use special nodes iterator
8228 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8229 while( anIter->more() ) {
8230 nodes[ iNode++ ] = cast2Node(anIter->next());
8234 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8235 while ( nIt->more() )
8236 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8238 nodes[ iNode ] = nodes[ 0 ];
8240 for ( iNode = 0; iNode < nbNodes; iNode++ )
8241 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8242 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8243 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8245 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8246 curElemList.push_back( e );
8250 // analyse the found
8252 int nbNewBorders = curElemList.size();
8253 if ( nbNewBorders == 0 ) {
8254 // no free border furthermore
8255 return !needTheLast;
8257 else if ( nbNewBorders == 1 ) {
8258 // one more element found
8260 nStart = nStartList.front();
8261 curElem = curElemList.front();
8262 theFaces.push_back( curElem );
8263 theNodes.push_back( nStart );
8266 // several continuations found
8267 list< const SMDS_MeshElement* >::iterator curElemIt;
8268 list< const SMDS_MeshNode* >::iterator nStartIt;
8269 // check if one of them reached the last node
8270 if ( needTheLast ) {
8271 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8272 curElemIt!= curElemList.end();
8273 curElemIt++, nStartIt++ )
8274 if ( *nStartIt == theLastNode ) {
8275 theFaces.push_back( *curElemIt );
8276 theNodes.push_back( *nStartIt );
8280 // find the best free border by the continuations
8281 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8282 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8283 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8284 curElemIt!= curElemList.end();
8285 curElemIt++, nStartIt++ )
8287 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8288 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8289 // find one more free border
8290 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8294 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8295 // choice: clear a worse one
8296 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8297 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8298 contNodes[ iWorse ].clear();
8299 contFaces[ iWorse ].clear();
8302 if ( contNodes[0].empty() && contNodes[1].empty() )
8305 // append the best free border
8306 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8307 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8308 theNodes.pop_back(); // remove nIgnore
8309 theNodes.pop_back(); // remove nStart
8310 theFaces.pop_back(); // remove curElem
8311 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8312 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8313 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8314 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8317 } // several continuations found
8318 } // while ( nStart != theLastNode )
8323 //=======================================================================
8324 //function : CheckFreeBorderNodes
8325 //purpose : Return true if the tree nodes are on a free border
8326 //=======================================================================
8328 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8329 const SMDS_MeshNode* theNode2,
8330 const SMDS_MeshNode* theNode3)
8332 list< const SMDS_MeshNode* > nodes;
8333 list< const SMDS_MeshElement* > faces;
8334 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8337 //=======================================================================
8338 //function : SewFreeBorder
8340 //=======================================================================
8342 SMESH_MeshEditor::Sew_Error
8343 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8344 const SMDS_MeshNode* theBordSecondNode,
8345 const SMDS_MeshNode* theBordLastNode,
8346 const SMDS_MeshNode* theSideFirstNode,
8347 const SMDS_MeshNode* theSideSecondNode,
8348 const SMDS_MeshNode* theSideThirdNode,
8349 const bool theSideIsFreeBorder,
8350 const bool toCreatePolygons,
8351 const bool toCreatePolyedrs)
8353 myLastCreatedElems.Clear();
8354 myLastCreatedNodes.Clear();
8356 MESSAGE("::SewFreeBorder()");
8357 Sew_Error aResult = SEW_OK;
8359 // ====================================
8360 // find side nodes and elements
8361 // ====================================
8363 list< const SMDS_MeshNode* > nSide[ 2 ];
8364 list< const SMDS_MeshElement* > eSide[ 2 ];
8365 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8366 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8370 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8371 nSide[0], eSide[0])) {
8372 MESSAGE(" Free Border 1 not found " );
8373 aResult = SEW_BORDER1_NOT_FOUND;
8375 if (theSideIsFreeBorder) {
8378 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8379 nSide[1], eSide[1])) {
8380 MESSAGE(" Free Border 2 not found " );
8381 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8384 if ( aResult != SEW_OK )
8387 if (!theSideIsFreeBorder) {
8391 // -------------------------------------------------------------------------
8393 // 1. If nodes to merge are not coincident, move nodes of the free border
8394 // from the coord sys defined by the direction from the first to last
8395 // nodes of the border to the correspondent sys of the side 2
8396 // 2. On the side 2, find the links most co-directed with the correspondent
8397 // links of the free border
8398 // -------------------------------------------------------------------------
8400 // 1. Since sewing may break if there are volumes to split on the side 2,
8401 // we wont move nodes but just compute new coordinates for them
8402 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8403 TNodeXYZMap nBordXYZ;
8404 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8405 list< const SMDS_MeshNode* >::iterator nBordIt;
8407 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8408 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8409 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8410 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8411 double tol2 = 1.e-8;
8412 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8413 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8414 // Need node movement.
8416 // find X and Z axes to create trsf
8417 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8419 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8421 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8424 gp_Ax3 toBordAx( Pb1, Zb, X );
8425 gp_Ax3 fromSideAx( Ps1, Zs, X );
8426 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8428 gp_Trsf toBordSys, fromSide2Sys;
8429 toBordSys.SetTransformation( toBordAx );
8430 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8431 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8434 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8435 const SMDS_MeshNode* n = *nBordIt;
8436 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8437 toBordSys.Transforms( xyz );
8438 fromSide2Sys.Transforms( xyz );
8439 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8443 // just insert nodes XYZ in the nBordXYZ map
8444 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8445 const SMDS_MeshNode* n = *nBordIt;
8446 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8450 // 2. On the side 2, find the links most co-directed with the correspondent
8451 // links of the free border
8453 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8454 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8455 sideNodes.push_back( theSideFirstNode );
8457 bool hasVolumes = false;
8458 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8459 set<long> foundSideLinkIDs, checkedLinkIDs;
8460 SMDS_VolumeTool volume;
8461 //const SMDS_MeshNode* faceNodes[ 4 ];
8463 const SMDS_MeshNode* sideNode;
8464 const SMDS_MeshElement* sideElem;
8465 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8466 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8467 nBordIt = bordNodes.begin();
8469 // border node position and border link direction to compare with
8470 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8471 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8472 // choose next side node by link direction or by closeness to
8473 // the current border node:
8474 bool searchByDir = ( *nBordIt != theBordLastNode );
8476 // find the next node on the Side 2
8478 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8480 checkedLinkIDs.clear();
8481 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8483 // loop on inverse elements of current node (prevSideNode) on the Side 2
8484 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8485 while ( invElemIt->more() )
8487 const SMDS_MeshElement* elem = invElemIt->next();
8488 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8489 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8490 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8491 bool isVolume = volume.Set( elem );
8492 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8493 if ( isVolume ) // --volume
8495 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8496 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8497 if(elem->IsQuadratic()) {
8498 const SMDS_VtkFace* F =
8499 dynamic_cast<const SMDS_VtkFace*>(elem);
8500 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8501 // use special nodes iterator
8502 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8503 while( anIter->more() ) {
8504 nodes[ iNode ] = cast2Node(anIter->next());
8505 if ( nodes[ iNode++ ] == prevSideNode )
8506 iPrevNode = iNode - 1;
8510 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8511 while ( nIt->more() ) {
8512 nodes[ iNode ] = cast2Node( nIt->next() );
8513 if ( nodes[ iNode++ ] == prevSideNode )
8514 iPrevNode = iNode - 1;
8517 // there are 2 links to check
8522 // loop on links, to be precise, on the second node of links
8523 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8524 const SMDS_MeshNode* n = nodes[ iNode ];
8526 if ( !volume.IsLinked( n, prevSideNode ))
8530 if ( iNode ) // a node before prevSideNode
8531 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8532 else // a node after prevSideNode
8533 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8535 // check if this link was already used
8536 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8537 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8538 if (!isJustChecked &&
8539 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8541 // test a link geometrically
8542 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8543 bool linkIsBetter = false;
8544 double dot = 0.0, dist = 0.0;
8545 if ( searchByDir ) { // choose most co-directed link
8546 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8547 linkIsBetter = ( dot > maxDot );
8549 else { // choose link with the node closest to bordPos
8550 dist = ( nextXYZ - bordPos ).SquareModulus();
8551 linkIsBetter = ( dist < minDist );
8553 if ( linkIsBetter ) {
8562 } // loop on inverse elements of prevSideNode
8565 MESSAGE(" Cant find path by links of the Side 2 ");
8566 return SEW_BAD_SIDE_NODES;
8568 sideNodes.push_back( sideNode );
8569 sideElems.push_back( sideElem );
8570 foundSideLinkIDs.insert ( linkID );
8571 prevSideNode = sideNode;
8573 if ( *nBordIt == theBordLastNode )
8574 searchByDir = false;
8576 // find the next border link to compare with
8577 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8578 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8579 // move to next border node if sideNode is before forward border node (bordPos)
8580 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8581 prevBordNode = *nBordIt;
8583 bordPos = nBordXYZ[ *nBordIt ];
8584 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8585 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8589 while ( sideNode != theSideSecondNode );
8591 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8592 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8593 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8595 } // end nodes search on the side 2
8597 // ============================
8598 // sew the border to the side 2
8599 // ============================
8601 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8602 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8604 TListOfListOfNodes nodeGroupsToMerge;
8605 if ( nbNodes[0] == nbNodes[1] ||
8606 ( theSideIsFreeBorder && !theSideThirdNode)) {
8608 // all nodes are to be merged
8610 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8611 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8612 nIt[0]++, nIt[1]++ )
8614 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8615 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8616 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8621 // insert new nodes into the border and the side to get equal nb of segments
8623 // get normalized parameters of nodes on the borders
8624 //double param[ 2 ][ maxNbNodes ];
8626 param[0] = new double [ maxNbNodes ];
8627 param[1] = new double [ maxNbNodes ];
8629 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8630 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8631 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8632 const SMDS_MeshNode* nPrev = *nIt;
8633 double bordLength = 0;
8634 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8635 const SMDS_MeshNode* nCur = *nIt;
8636 gp_XYZ segment (nCur->X() - nPrev->X(),
8637 nCur->Y() - nPrev->Y(),
8638 nCur->Z() - nPrev->Z());
8639 double segmentLen = segment.Modulus();
8640 bordLength += segmentLen;
8641 param[ iBord ][ iNode ] = bordLength;
8644 // normalize within [0,1]
8645 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8646 param[ iBord ][ iNode ] /= bordLength;
8650 // loop on border segments
8651 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8652 int i[ 2 ] = { 0, 0 };
8653 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8654 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8656 TElemOfNodeListMap insertMap;
8657 TElemOfNodeListMap::iterator insertMapIt;
8659 // key: elem to insert nodes into
8660 // value: 2 nodes to insert between + nodes to be inserted
8662 bool next[ 2 ] = { false, false };
8664 // find min adjacent segment length after sewing
8665 double nextParam = 10., prevParam = 0;
8666 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8667 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8668 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8669 if ( i[ iBord ] > 0 )
8670 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8672 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8673 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8674 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8676 // choose to insert or to merge nodes
8677 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8678 if ( Abs( du ) <= minSegLen * 0.2 ) {
8681 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8682 const SMDS_MeshNode* n0 = *nIt[0];
8683 const SMDS_MeshNode* n1 = *nIt[1];
8684 nodeGroupsToMerge.back().push_back( n1 );
8685 nodeGroupsToMerge.back().push_back( n0 );
8686 // position of node of the border changes due to merge
8687 param[ 0 ][ i[0] ] += du;
8688 // move n1 for the sake of elem shape evaluation during insertion.
8689 // n1 will be removed by MergeNodes() anyway
8690 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8691 next[0] = next[1] = true;
8696 int intoBord = ( du < 0 ) ? 0 : 1;
8697 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8698 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8699 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8700 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8701 if ( intoBord == 1 ) {
8702 // move node of the border to be on a link of elem of the side
8703 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8704 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8705 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8706 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8707 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8709 insertMapIt = insertMap.find( elem );
8710 bool notFound = ( insertMapIt == insertMap.end() );
8711 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8713 // insert into another link of the same element:
8714 // 1. perform insertion into the other link of the elem
8715 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8716 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8717 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8718 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8719 // 2. perform insertion into the link of adjacent faces
8721 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8723 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8727 if (toCreatePolyedrs) {
8728 // perform insertion into the links of adjacent volumes
8729 UpdateVolumes(n12, n22, nodeList);
8731 // 3. find an element appeared on n1 and n2 after the insertion
8732 insertMap.erase( elem );
8733 elem = findAdjacentFace( n1, n2, 0 );
8735 if ( notFound || otherLink ) {
8736 // add element and nodes of the side into the insertMap
8737 insertMapIt = insertMap.insert
8738 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8739 (*insertMapIt).second.push_back( n1 );
8740 (*insertMapIt).second.push_back( n2 );
8742 // add node to be inserted into elem
8743 (*insertMapIt).second.push_back( nIns );
8744 next[ 1 - intoBord ] = true;
8747 // go to the next segment
8748 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8749 if ( next[ iBord ] ) {
8750 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8752 nPrev[ iBord ] = *nIt[ iBord ];
8753 nIt[ iBord ]++; i[ iBord ]++;
8757 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8759 // perform insertion of nodes into elements
8761 for (insertMapIt = insertMap.begin();
8762 insertMapIt != insertMap.end();
8765 const SMDS_MeshElement* elem = (*insertMapIt).first;
8766 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8767 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8768 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8770 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8772 if ( !theSideIsFreeBorder ) {
8773 // look for and insert nodes into the faces adjacent to elem
8775 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8777 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8782 if (toCreatePolyedrs) {
8783 // perform insertion into the links of adjacent volumes
8784 UpdateVolumes(n1, n2, nodeList);
8790 } // end: insert new nodes
8792 MergeNodes ( nodeGroupsToMerge );
8797 //=======================================================================
8798 //function : InsertNodesIntoLink
8799 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8800 // and theBetweenNode2 and split theElement
8801 //=======================================================================
8803 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8804 const SMDS_MeshNode* theBetweenNode1,
8805 const SMDS_MeshNode* theBetweenNode2,
8806 list<const SMDS_MeshNode*>& theNodesToInsert,
8807 const bool toCreatePoly)
8809 if ( theFace->GetType() != SMDSAbs_Face ) return;
8811 // find indices of 2 link nodes and of the rest nodes
8812 int iNode = 0, il1, il2, i3, i4;
8813 il1 = il2 = i3 = i4 = -1;
8814 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8815 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8817 if(theFace->IsQuadratic()) {
8818 const SMDS_VtkFace* F =
8819 dynamic_cast<const SMDS_VtkFace*>(theFace);
8820 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8821 // use special nodes iterator
8822 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8823 while( anIter->more() ) {
8824 const SMDS_MeshNode* n = cast2Node(anIter->next());
8825 if ( n == theBetweenNode1 )
8827 else if ( n == theBetweenNode2 )
8833 nodes[ iNode++ ] = n;
8837 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8838 while ( nodeIt->more() ) {
8839 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8840 if ( n == theBetweenNode1 )
8842 else if ( n == theBetweenNode2 )
8848 nodes[ iNode++ ] = n;
8851 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8854 // arrange link nodes to go one after another regarding the face orientation
8855 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8856 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8861 aNodesToInsert.reverse();
8863 // check that not link nodes of a quadrangles are in good order
8864 int nbFaceNodes = theFace->NbNodes();
8865 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8871 if (toCreatePoly || theFace->IsPoly()) {
8874 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8876 // add nodes of face up to first node of link
8879 if(theFace->IsQuadratic()) {
8880 const SMDS_VtkFace* F =
8881 dynamic_cast<const SMDS_VtkFace*>(theFace);
8882 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8883 // use special nodes iterator
8884 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8885 while( anIter->more() && !isFLN ) {
8886 const SMDS_MeshNode* n = cast2Node(anIter->next());
8887 poly_nodes[iNode++] = n;
8888 if (n == nodes[il1]) {
8892 // add nodes to insert
8893 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8894 for (; nIt != aNodesToInsert.end(); nIt++) {
8895 poly_nodes[iNode++] = *nIt;
8897 // add nodes of face starting from last node of link
8898 while ( anIter->more() ) {
8899 poly_nodes[iNode++] = cast2Node(anIter->next());
8903 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8904 while ( nodeIt->more() && !isFLN ) {
8905 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8906 poly_nodes[iNode++] = n;
8907 if (n == nodes[il1]) {
8911 // add nodes to insert
8912 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8913 for (; nIt != aNodesToInsert.end(); nIt++) {
8914 poly_nodes[iNode++] = *nIt;
8916 // add nodes of face starting from last node of link
8917 while ( nodeIt->more() ) {
8918 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8919 poly_nodes[iNode++] = n;
8923 // edit or replace the face
8924 SMESHDS_Mesh *aMesh = GetMeshDS();
8926 if (theFace->IsPoly()) {
8927 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8930 int aShapeId = FindShape( theFace );
8932 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8933 myLastCreatedElems.Append(newElem);
8934 if ( aShapeId && newElem )
8935 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8937 aMesh->RemoveElement(theFace);
8942 SMESHDS_Mesh *aMesh = GetMeshDS();
8943 if( !theFace->IsQuadratic() ) {
8945 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8946 int nbLinkNodes = 2 + aNodesToInsert.size();
8947 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8948 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8949 linkNodes[ 0 ] = nodes[ il1 ];
8950 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8951 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8952 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8953 linkNodes[ iNode++ ] = *nIt;
8955 // decide how to split a quadrangle: compare possible variants
8956 // and choose which of splits to be a quadrangle
8957 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8958 if ( nbFaceNodes == 3 ) {
8959 iBestQuad = nbSplits;
8962 else if ( nbFaceNodes == 4 ) {
8963 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8964 double aBestRate = DBL_MAX;
8965 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8967 double aBadRate = 0;
8968 // evaluate elements quality
8969 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8970 if ( iSplit == iQuad ) {
8971 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8975 aBadRate += getBadRate( &quad, aCrit );
8978 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8980 nodes[ iSplit < iQuad ? i4 : i3 ]);
8981 aBadRate += getBadRate( &tria, aCrit );
8985 if ( aBadRate < aBestRate ) {
8987 aBestRate = aBadRate;
8992 // create new elements
8993 int aShapeId = FindShape( theFace );
8996 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8997 SMDS_MeshElement* newElem = 0;
8998 if ( iSplit == iBestQuad )
8999 newElem = aMesh->AddFace (linkNodes[ i1++ ],
9004 newElem = aMesh->AddFace (linkNodes[ i1++ ],
9006 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9007 myLastCreatedElems.Append(newElem);
9008 if ( aShapeId && newElem )
9009 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9012 // change nodes of theFace
9013 const SMDS_MeshNode* newNodes[ 4 ];
9014 newNodes[ 0 ] = linkNodes[ i1 ];
9015 newNodes[ 1 ] = linkNodes[ i2 ];
9016 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9017 newNodes[ 3 ] = nodes[ i4 ];
9018 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9019 const SMDS_MeshElement* newElem = 0;
9020 if (iSplit == iBestQuad)
9021 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9023 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9024 myLastCreatedElems.Append(newElem);
9025 if ( aShapeId && newElem )
9026 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9027 } // end if(!theFace->IsQuadratic())
9028 else { // theFace is quadratic
9029 // we have to split theFace on simple triangles and one simple quadrangle
9031 int nbshift = tmp*2;
9032 // shift nodes in nodes[] by nbshift
9034 for(i=0; i<nbshift; i++) {
9035 const SMDS_MeshNode* n = nodes[0];
9036 for(j=0; j<nbFaceNodes-1; j++) {
9037 nodes[j] = nodes[j+1];
9039 nodes[nbFaceNodes-1] = n;
9041 il1 = il1 - nbshift;
9042 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9043 // n0 n1 n2 n0 n1 n2
9044 // +-----+-----+ +-----+-----+
9053 // create new elements
9054 int aShapeId = FindShape( theFace );
9057 if(nbFaceNodes==6) { // quadratic triangle
9058 SMDS_MeshElement* newElem =
9059 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9060 myLastCreatedElems.Append(newElem);
9061 if ( aShapeId && newElem )
9062 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9063 if(theFace->IsMediumNode(nodes[il1])) {
9064 // create quadrangle
9065 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9066 myLastCreatedElems.Append(newElem);
9067 if ( aShapeId && newElem )
9068 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9074 // create quadrangle
9075 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9076 myLastCreatedElems.Append(newElem);
9077 if ( aShapeId && newElem )
9078 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9084 else { // nbFaceNodes==8 - quadratic quadrangle
9085 SMDS_MeshElement* newElem =
9086 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9087 myLastCreatedElems.Append(newElem);
9088 if ( aShapeId && newElem )
9089 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9090 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9091 myLastCreatedElems.Append(newElem);
9092 if ( aShapeId && newElem )
9093 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9094 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9095 myLastCreatedElems.Append(newElem);
9096 if ( aShapeId && newElem )
9097 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9098 if(theFace->IsMediumNode(nodes[il1])) {
9099 // create quadrangle
9100 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9101 myLastCreatedElems.Append(newElem);
9102 if ( aShapeId && newElem )
9103 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9109 // create quadrangle
9110 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9111 myLastCreatedElems.Append(newElem);
9112 if ( aShapeId && newElem )
9113 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9119 // create needed triangles using n1,n2,n3 and inserted nodes
9120 int nbn = 2 + aNodesToInsert.size();
9121 //const SMDS_MeshNode* aNodes[nbn];
9122 vector<const SMDS_MeshNode*> aNodes(nbn);
9123 aNodes[0] = nodes[n1];
9124 aNodes[nbn-1] = nodes[n2];
9125 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9126 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9127 aNodes[iNode++] = *nIt;
9129 for(i=1; i<nbn; i++) {
9130 SMDS_MeshElement* newElem =
9131 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9132 myLastCreatedElems.Append(newElem);
9133 if ( aShapeId && newElem )
9134 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9138 aMesh->RemoveElement(theFace);
9141 //=======================================================================
9142 //function : UpdateVolumes
9144 //=======================================================================
9145 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9146 const SMDS_MeshNode* theBetweenNode2,
9147 list<const SMDS_MeshNode*>& theNodesToInsert)
9149 myLastCreatedElems.Clear();
9150 myLastCreatedNodes.Clear();
9152 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9153 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9154 const SMDS_MeshElement* elem = invElemIt->next();
9156 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9157 SMDS_VolumeTool aVolume (elem);
9158 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9161 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9162 int iface, nbFaces = aVolume.NbFaces();
9163 vector<const SMDS_MeshNode *> poly_nodes;
9164 vector<int> quantities (nbFaces);
9166 for (iface = 0; iface < nbFaces; iface++) {
9167 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9168 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9169 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9171 for (int inode = 0; inode < nbFaceNodes; inode++) {
9172 poly_nodes.push_back(faceNodes[inode]);
9174 if (nbInserted == 0) {
9175 if (faceNodes[inode] == theBetweenNode1) {
9176 if (faceNodes[inode + 1] == theBetweenNode2) {
9177 nbInserted = theNodesToInsert.size();
9179 // add nodes to insert
9180 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9181 for (; nIt != theNodesToInsert.end(); nIt++) {
9182 poly_nodes.push_back(*nIt);
9186 else if (faceNodes[inode] == theBetweenNode2) {
9187 if (faceNodes[inode + 1] == theBetweenNode1) {
9188 nbInserted = theNodesToInsert.size();
9190 // add nodes to insert in reversed order
9191 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9193 for (; nIt != theNodesToInsert.begin(); nIt--) {
9194 poly_nodes.push_back(*nIt);
9196 poly_nodes.push_back(*nIt);
9203 quantities[iface] = nbFaceNodes + nbInserted;
9206 // Replace or update the volume
9207 SMESHDS_Mesh *aMesh = GetMeshDS();
9209 if (elem->IsPoly()) {
9210 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9214 int aShapeId = FindShape( elem );
9216 SMDS_MeshElement* newElem =
9217 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9218 myLastCreatedElems.Append(newElem);
9219 if (aShapeId && newElem)
9220 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9222 aMesh->RemoveElement(elem);
9227 //=======================================================================
9229 * \brief Convert elements contained in a submesh to quadratic
9230 * \return int - nb of checked elements
9232 //=======================================================================
9234 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9235 SMESH_MesherHelper& theHelper,
9236 const bool theForce3d)
9239 if( !theSm ) return nbElem;
9241 vector<int> nbNodeInFaces;
9242 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9243 while(ElemItr->more())
9246 const SMDS_MeshElement* elem = ElemItr->next();
9247 if( !elem || elem->IsQuadratic() ) continue;
9249 int id = elem->GetID();
9250 int nbNodes = elem->NbNodes();
9251 SMDSAbs_ElementType aType = elem->GetType();
9253 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9254 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9255 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9257 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9259 const SMDS_MeshElement* NewElem = 0;
9265 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9273 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9276 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9279 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9284 case SMDSAbs_Volume :
9289 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9292 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9295 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9298 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9299 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9302 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9309 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9311 theSm->AddElement( NewElem );
9313 // if (!GetMeshDS()->isCompacted())
9314 // GetMeshDS()->compactMesh();
9318 //=======================================================================
9319 //function : ConvertToQuadratic
9321 //=======================================================================
9322 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9324 SMESHDS_Mesh* meshDS = GetMeshDS();
9326 SMESH_MesherHelper aHelper(*myMesh);
9327 aHelper.SetIsQuadratic( true );
9329 int nbCheckedElems = 0;
9330 if ( myMesh->HasShapeToMesh() )
9332 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9334 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9335 while ( smIt->more() ) {
9336 SMESH_subMesh* sm = smIt->next();
9337 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9338 aHelper.SetSubShape( sm->GetSubShape() );
9339 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9344 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9345 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9347 SMESHDS_SubMesh *smDS = 0;
9348 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9349 while(aEdgeItr->more())
9351 const SMDS_MeshEdge* edge = aEdgeItr->next();
9352 if(edge && !edge->IsQuadratic())
9354 int id = edge->GetID();
9355 //MESSAGE("edge->GetID() " << id);
9356 const SMDS_MeshNode* n1 = edge->GetNode(0);
9357 const SMDS_MeshNode* n2 = edge->GetNode(1);
9359 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9361 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9362 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9365 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9366 while(aFaceItr->more())
9368 const SMDS_MeshFace* face = aFaceItr->next();
9369 if(!face || face->IsQuadratic() ) continue;
9371 int id = face->GetID();
9372 int nbNodes = face->NbNodes();
9373 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9375 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9377 SMDS_MeshFace * NewFace = 0;
9381 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9384 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9387 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9389 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9391 vector<int> nbNodeInFaces;
9392 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9393 while(aVolumeItr->more())
9395 const SMDS_MeshVolume* volume = aVolumeItr->next();
9396 if(!volume || volume->IsQuadratic() ) continue;
9398 int id = volume->GetID();
9399 int nbNodes = volume->NbNodes();
9400 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9401 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9402 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9404 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9406 SMDS_MeshVolume * NewVolume = 0;
9410 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9411 nodes[3], id, theForce3d );
9414 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9415 nodes[3], nodes[4], id, theForce3d);
9418 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9419 nodes[3], nodes[4], nodes[5], id, theForce3d);
9422 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9423 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9426 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9428 ReplaceElemInGroups(volume, NewVolume, meshDS);
9433 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9434 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9435 aHelper.FixQuadraticElements();
9439 //================================================================================
9441 * \brief Makes given elements quadratic
9442 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9443 * \param theElements - elements to make quadratic
9445 //================================================================================
9447 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9448 TIDSortedElemSet& theElements)
9450 if ( theElements.empty() ) return;
9452 // we believe that all theElements are of the same type
9453 SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9455 // get all nodes shared by theElements
9456 TIDSortedNodeSet allNodes;
9457 TIDSortedElemSet::iterator eIt = theElements.begin();
9458 for ( ; eIt != theElements.end(); ++eIt )
9459 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9461 // complete theElements with elements of lower dim whose all nodes are in allNodes
9463 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9464 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9465 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9466 for ( ; nIt != allNodes.end(); ++nIt )
9468 const SMDS_MeshNode* n = *nIt;
9469 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9470 while ( invIt->more() )
9472 const SMDS_MeshElement* e = invIt->next();
9473 if ( e->IsQuadratic() )
9475 quadAdjacentElems[ e->GetType() ].insert( e );
9478 if ( e->GetType() >= elemType )
9480 continue; // same type of more complex linear element
9483 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9484 continue; // e is already checked
9488 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9489 while ( nodeIt->more() && allIn )
9490 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9492 theElements.insert(e );
9496 SMESH_MesherHelper helper(*myMesh);
9497 helper.SetIsQuadratic( true );
9499 // add links of quadratic adjacent elements to the helper
9501 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9502 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9503 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9505 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9507 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9508 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9509 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9511 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9513 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9514 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9515 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9517 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9520 // make quadratic elements instead of linear ones
9522 SMESHDS_Mesh* meshDS = GetMeshDS();
9523 SMESHDS_SubMesh* smDS = 0;
9524 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9526 const SMDS_MeshElement* elem = *eIt;
9527 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9530 int id = elem->GetID();
9531 SMDSAbs_ElementType type = elem->GetType();
9532 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9534 if ( !smDS || !smDS->Contains( elem ))
9535 smDS = meshDS->MeshElements( elem->getshapeId() );
9536 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9538 SMDS_MeshElement * newElem = 0;
9539 switch( nodes.size() )
9541 case 4: // cases for most multiple element types go first (for optimization)
9542 if ( type == SMDSAbs_Volume )
9543 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9545 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9548 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9549 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9552 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9555 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9558 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9559 nodes[4], id, theForce3d);
9562 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9563 nodes[4], nodes[5], id, theForce3d);
9567 ReplaceElemInGroups( elem, newElem, meshDS);
9568 if( newElem && smDS )
9569 smDS->AddElement( newElem );
9572 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9573 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9574 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9575 helper.FixQuadraticElements();
9579 //=======================================================================
9581 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9582 * \return int - nb of checked elements
9584 //=======================================================================
9586 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9587 SMDS_ElemIteratorPtr theItr,
9588 const int theShapeID)
9591 SMESHDS_Mesh* meshDS = GetMeshDS();
9593 while( theItr->more() )
9595 const SMDS_MeshElement* elem = theItr->next();
9597 if( elem && elem->IsQuadratic())
9599 int id = elem->GetID();
9600 int nbCornerNodes = elem->NbCornerNodes();
9601 SMDSAbs_ElementType aType = elem->GetType();
9603 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9605 //remove a quadratic element
9606 if ( !theSm || !theSm->Contains( elem ))
9607 theSm = meshDS->MeshElements( elem->getshapeId() );
9608 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9610 // remove medium nodes
9611 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9612 if ( nodes[i]->NbInverseElements() == 0 )
9613 meshDS->RemoveFreeNode( nodes[i], theSm );
9615 // add a linear element
9616 nodes.resize( nbCornerNodes );
9617 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9618 ReplaceElemInGroups(elem, newElem, meshDS);
9619 if( theSm && newElem )
9620 theSm->AddElement( newElem );
9626 //=======================================================================
9627 //function : ConvertFromQuadratic
9629 //=======================================================================
9631 bool SMESH_MeshEditor::ConvertFromQuadratic()
9633 int nbCheckedElems = 0;
9634 if ( myMesh->HasShapeToMesh() )
9636 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9638 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9639 while ( smIt->more() ) {
9640 SMESH_subMesh* sm = smIt->next();
9641 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9642 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9648 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9649 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9651 SMESHDS_SubMesh *aSM = 0;
9652 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9660 //================================================================================
9662 * \brief Return true if all medium nodes of the element are in the node set
9664 //================================================================================
9666 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9668 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9669 if ( !nodeSet.count( elem->GetNode(i) ))
9675 //================================================================================
9677 * \brief Makes given elements linear
9679 //================================================================================
9681 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9683 if ( theElements.empty() ) return;
9685 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9686 set<int> mediumNodeIDs;
9687 TIDSortedElemSet::iterator eIt = theElements.begin();
9688 for ( ; eIt != theElements.end(); ++eIt )
9690 const SMDS_MeshElement* e = *eIt;
9691 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9692 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9695 // replace given elements by linear ones
9696 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9697 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9698 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9700 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9701 // except those elements sharing medium nodes of quadratic element whose medium nodes
9702 // are not all in mediumNodeIDs
9704 // get remaining medium nodes
9705 TIDSortedNodeSet mediumNodes;
9706 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9707 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9708 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9709 mediumNodes.insert( mediumNodes.end(), n );
9711 // find more quadratic elements to convert
9712 TIDSortedElemSet moreElemsToConvert;
9713 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9714 for ( ; nIt != mediumNodes.end(); ++nIt )
9716 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9717 while ( invIt->more() )
9719 const SMDS_MeshElement* e = invIt->next();
9720 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9722 // find a more complex element including e and
9723 // whose medium nodes are not in mediumNodes
9724 bool complexFound = false;
9725 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9727 SMDS_ElemIteratorPtr invIt2 =
9728 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9729 while ( invIt2->more() )
9731 const SMDS_MeshElement* eComplex = invIt2->next();
9732 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9734 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9735 if ( nbCommonNodes == e->NbNodes())
9737 complexFound = true;
9738 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9744 if ( !complexFound )
9745 moreElemsToConvert.insert( e );
9749 elemIt = SMDS_ElemIteratorPtr
9750 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9751 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9754 //=======================================================================
9755 //function : SewSideElements
9757 //=======================================================================
9759 SMESH_MeshEditor::Sew_Error
9760 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9761 TIDSortedElemSet& theSide2,
9762 const SMDS_MeshNode* theFirstNode1,
9763 const SMDS_MeshNode* theFirstNode2,
9764 const SMDS_MeshNode* theSecondNode1,
9765 const SMDS_MeshNode* theSecondNode2)
9767 myLastCreatedElems.Clear();
9768 myLastCreatedNodes.Clear();
9770 MESSAGE ("::::SewSideElements()");
9771 if ( theSide1.size() != theSide2.size() )
9772 return SEW_DIFF_NB_OF_ELEMENTS;
9774 Sew_Error aResult = SEW_OK;
9776 // 1. Build set of faces representing each side
9777 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9778 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9780 // =======================================================================
9781 // 1. Build set of faces representing each side:
9782 // =======================================================================
9783 // a. build set of nodes belonging to faces
9784 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9785 // c. create temporary faces representing side of volumes if correspondent
9786 // face does not exist
9788 SMESHDS_Mesh* aMesh = GetMeshDS();
9789 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9790 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9791 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9792 set<const SMDS_MeshElement*> volSet1, volSet2;
9793 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9794 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9795 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9796 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9797 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9798 int iSide, iFace, iNode;
9800 list<const SMDS_MeshElement* > tempFaceList;
9801 for ( iSide = 0; iSide < 2; iSide++ ) {
9802 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9803 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9804 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9805 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9806 set<const SMDS_MeshElement*>::iterator vIt;
9807 TIDSortedElemSet::iterator eIt;
9808 set<const SMDS_MeshNode*>::iterator nIt;
9810 // check that given nodes belong to given elements
9811 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9812 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9813 int firstIndex = -1, secondIndex = -1;
9814 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9815 const SMDS_MeshElement* elem = *eIt;
9816 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9817 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9818 if ( firstIndex > -1 && secondIndex > -1 ) break;
9820 if ( firstIndex < 0 || secondIndex < 0 ) {
9821 // we can simply return until temporary faces created
9822 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9825 // -----------------------------------------------------------
9826 // 1a. Collect nodes of existing faces
9827 // and build set of face nodes in order to detect missing
9828 // faces corresponding to sides of volumes
9829 // -----------------------------------------------------------
9831 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9833 // loop on the given element of a side
9834 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9835 //const SMDS_MeshElement* elem = *eIt;
9836 const SMDS_MeshElement* elem = *eIt;
9837 if ( elem->GetType() == SMDSAbs_Face ) {
9838 faceSet->insert( elem );
9839 set <const SMDS_MeshNode*> faceNodeSet;
9840 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9841 while ( nodeIt->more() ) {
9842 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9843 nodeSet->insert( n );
9844 faceNodeSet.insert( n );
9846 setOfFaceNodeSet.insert( faceNodeSet );
9848 else if ( elem->GetType() == SMDSAbs_Volume )
9849 volSet->insert( elem );
9851 // ------------------------------------------------------------------------------
9852 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9853 // ------------------------------------------------------------------------------
9855 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9856 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9857 while ( fIt->more() ) { // loop on faces sharing a node
9858 const SMDS_MeshElement* f = fIt->next();
9859 if ( faceSet->find( f ) == faceSet->end() ) {
9860 // check if all nodes are in nodeSet and
9861 // complete setOfFaceNodeSet if they are
9862 set <const SMDS_MeshNode*> faceNodeSet;
9863 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9864 bool allInSet = true;
9865 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9866 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9867 if ( nodeSet->find( n ) == nodeSet->end() )
9870 faceNodeSet.insert( n );
9873 faceSet->insert( f );
9874 setOfFaceNodeSet.insert( faceNodeSet );
9880 // -------------------------------------------------------------------------
9881 // 1c. Create temporary faces representing sides of volumes if correspondent
9882 // face does not exist
9883 // -------------------------------------------------------------------------
9885 if ( !volSet->empty() ) {
9886 //int nodeSetSize = nodeSet->size();
9888 // loop on given volumes
9889 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9890 SMDS_VolumeTool vol (*vIt);
9891 // loop on volume faces: find free faces
9892 // --------------------------------------
9893 list<const SMDS_MeshElement* > freeFaceList;
9894 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9895 if ( !vol.IsFreeFace( iFace ))
9897 // check if there is already a face with same nodes in a face set
9898 const SMDS_MeshElement* aFreeFace = 0;
9899 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9900 int nbNodes = vol.NbFaceNodes( iFace );
9901 set <const SMDS_MeshNode*> faceNodeSet;
9902 vol.GetFaceNodes( iFace, faceNodeSet );
9903 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9905 // no such a face is given but it still can exist, check it
9906 if ( nbNodes == 3 ) {
9907 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9909 else if ( nbNodes == 4 ) {
9910 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9913 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9914 aFreeFace = aMesh->FindFace(poly_nodes);
9918 // create a temporary face
9919 if ( nbNodes == 3 ) {
9920 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9921 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9923 else if ( nbNodes == 4 ) {
9924 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9925 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9928 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9929 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9930 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9934 freeFaceList.push_back( aFreeFace );
9935 tempFaceList.push_back( aFreeFace );
9938 } // loop on faces of a volume
9940 // choose one of several free faces
9941 // --------------------------------------
9942 if ( freeFaceList.size() > 1 ) {
9943 // choose a face having max nb of nodes shared by other elems of a side
9944 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9945 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9946 while ( fIt != freeFaceList.end() ) { // loop on free faces
9947 int nbSharedNodes = 0;
9948 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9949 while ( nodeIt->more() ) { // loop on free face nodes
9950 const SMDS_MeshNode* n =
9951 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9952 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9953 while ( invElemIt->more() ) {
9954 const SMDS_MeshElement* e = invElemIt->next();
9955 if ( faceSet->find( e ) != faceSet->end() )
9957 if ( elemSet->find( e ) != elemSet->end() )
9961 if ( nbSharedNodes >= maxNbNodes ) {
9962 maxNbNodes = nbSharedNodes;
9966 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9968 if ( freeFaceList.size() > 1 )
9970 // could not choose one face, use another way
9971 // choose a face most close to the bary center of the opposite side
9972 gp_XYZ aBC( 0., 0., 0. );
9973 set <const SMDS_MeshNode*> addedNodes;
9974 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9975 eIt = elemSet2->begin();
9976 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9977 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9978 while ( nodeIt->more() ) { // loop on free face nodes
9979 const SMDS_MeshNode* n =
9980 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9981 if ( addedNodes.insert( n ).second )
9982 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9985 aBC /= addedNodes.size();
9986 double minDist = DBL_MAX;
9987 fIt = freeFaceList.begin();
9988 while ( fIt != freeFaceList.end() ) { // loop on free faces
9990 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9991 while ( nodeIt->more() ) { // loop on free face nodes
9992 const SMDS_MeshNode* n =
9993 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9994 gp_XYZ p( n->X(),n->Y(),n->Z() );
9995 dist += ( aBC - p ).SquareModulus();
9997 if ( dist < minDist ) {
9999 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10002 fIt = freeFaceList.erase( fIt++ );
10005 } // choose one of several free faces of a volume
10007 if ( freeFaceList.size() == 1 ) {
10008 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10009 faceSet->insert( aFreeFace );
10010 // complete a node set with nodes of a found free face
10011 // for ( iNode = 0; iNode < ; iNode++ )
10012 // nodeSet->insert( fNodes[ iNode ] );
10015 } // loop on volumes of a side
10017 // // complete a set of faces if new nodes in a nodeSet appeared
10018 // // ----------------------------------------------------------
10019 // if ( nodeSetSize != nodeSet->size() ) {
10020 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10021 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10022 // while ( fIt->more() ) { // loop on faces sharing a node
10023 // const SMDS_MeshElement* f = fIt->next();
10024 // if ( faceSet->find( f ) == faceSet->end() ) {
10025 // // check if all nodes are in nodeSet and
10026 // // complete setOfFaceNodeSet if they are
10027 // set <const SMDS_MeshNode*> faceNodeSet;
10028 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10029 // bool allInSet = true;
10030 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10031 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10032 // if ( nodeSet->find( n ) == nodeSet->end() )
10033 // allInSet = false;
10035 // faceNodeSet.insert( n );
10037 // if ( allInSet ) {
10038 // faceSet->insert( f );
10039 // setOfFaceNodeSet.insert( faceNodeSet );
10045 } // Create temporary faces, if there are volumes given
10048 if ( faceSet1.size() != faceSet2.size() ) {
10049 // delete temporary faces: they are in reverseElements of actual nodes
10050 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10051 // while ( tmpFaceIt->more() )
10052 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10053 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10054 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10055 // aMesh->RemoveElement(*tmpFaceIt);
10056 MESSAGE("Diff nb of faces");
10057 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10060 // ============================================================
10061 // 2. Find nodes to merge:
10062 // bind a node to remove to a node to put instead
10063 // ============================================================
10065 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10066 if ( theFirstNode1 != theFirstNode2 )
10067 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10068 if ( theSecondNode1 != theSecondNode2 )
10069 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10071 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10072 set< long > linkIdSet; // links to process
10073 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10075 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10076 list< NLink > linkList[2];
10077 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10078 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10079 // loop on links in linkList; find faces by links and append links
10080 // of the found faces to linkList
10081 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10082 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10083 NLink link[] = { *linkIt[0], *linkIt[1] };
10084 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10085 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10088 // by links, find faces in the face sets,
10089 // and find indices of link nodes in the found faces;
10090 // in a face set, there is only one or no face sharing a link
10091 // ---------------------------------------------------------------
10093 const SMDS_MeshElement* face[] = { 0, 0 };
10094 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10095 vector<const SMDS_MeshNode*> fnodes1(9);
10096 vector<const SMDS_MeshNode*> fnodes2(9);
10097 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10098 vector<const SMDS_MeshNode*> notLinkNodes1(6);
10099 vector<const SMDS_MeshNode*> notLinkNodes2(6);
10100 int iLinkNode[2][2];
10101 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10102 const SMDS_MeshNode* n1 = link[iSide].first;
10103 const SMDS_MeshNode* n2 = link[iSide].second;
10104 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10105 set< const SMDS_MeshElement* > fMap;
10106 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10107 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10108 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10109 while ( fIt->more() ) { // loop on faces sharing a node
10110 const SMDS_MeshElement* f = fIt->next();
10111 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10112 ! fMap.insert( f ).second ) // f encounters twice
10114 if ( face[ iSide ] ) {
10115 MESSAGE( "2 faces per link " );
10116 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10120 faceSet->erase( f );
10121 // get face nodes and find ones of a link
10126 fnodes1.resize(f->NbNodes()+1);
10127 notLinkNodes1.resize(f->NbNodes()-2);
10130 fnodes2.resize(f->NbNodes()+1);
10131 notLinkNodes2.resize(f->NbNodes()-2);
10134 if(!f->IsQuadratic()) {
10135 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10136 while ( nIt->more() ) {
10137 const SMDS_MeshNode* n =
10138 static_cast<const SMDS_MeshNode*>( nIt->next() );
10140 iLinkNode[ iSide ][ 0 ] = iNode;
10142 else if ( n == n2 ) {
10143 iLinkNode[ iSide ][ 1 ] = iNode;
10145 //else if ( notLinkNodes[ iSide ][ 0 ] )
10146 // notLinkNodes[ iSide ][ 1 ] = n;
10148 // notLinkNodes[ iSide ][ 0 ] = n;
10152 notLinkNodes1[nbl] = n;
10153 //notLinkNodes1.push_back(n);
10155 notLinkNodes2[nbl] = n;
10156 //notLinkNodes2.push_back(n);
10158 //faceNodes[ iSide ][ iNode++ ] = n;
10160 fnodes1[iNode++] = n;
10163 fnodes2[iNode++] = n;
10167 else { // f->IsQuadratic()
10168 const SMDS_VtkFace* F =
10169 dynamic_cast<const SMDS_VtkFace*>(f);
10170 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10171 // use special nodes iterator
10172 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10173 while ( anIter->more() ) {
10174 const SMDS_MeshNode* n =
10175 static_cast<const SMDS_MeshNode*>( anIter->next() );
10177 iLinkNode[ iSide ][ 0 ] = iNode;
10179 else if ( n == n2 ) {
10180 iLinkNode[ iSide ][ 1 ] = iNode;
10185 notLinkNodes1[nbl] = n;
10188 notLinkNodes2[nbl] = n;
10192 fnodes1[iNode++] = n;
10195 fnodes2[iNode++] = n;
10199 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10201 fnodes1[iNode] = fnodes1[0];
10204 fnodes2[iNode] = fnodes1[0];
10211 // check similarity of elements of the sides
10212 if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10213 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10214 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10215 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10218 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10220 break; // do not return because it s necessary to remove tmp faces
10223 // set nodes to merge
10224 // -------------------
10226 if ( face[0] && face[1] ) {
10227 int nbNodes = face[0]->NbNodes();
10228 if ( nbNodes != face[1]->NbNodes() ) {
10229 MESSAGE("Diff nb of face nodes");
10230 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10231 break; // do not return because it s necessary to remove tmp faces
10233 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10234 if ( nbNodes == 3 ) {
10235 //nReplaceMap.insert( TNodeNodeMap::value_type
10236 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10237 nReplaceMap.insert( TNodeNodeMap::value_type
10238 ( notLinkNodes1[0], notLinkNodes2[0] ));
10241 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10242 // analyse link orientation in faces
10243 int i1 = iLinkNode[ iSide ][ 0 ];
10244 int i2 = iLinkNode[ iSide ][ 1 ];
10245 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10246 // if notLinkNodes are the first and the last ones, then
10247 // their order does not correspond to the link orientation
10248 if (( i1 == 1 && i2 == 2 ) ||
10249 ( i1 == 2 && i2 == 1 ))
10250 reverse[ iSide ] = !reverse[ iSide ];
10252 if ( reverse[0] == reverse[1] ) {
10253 //nReplaceMap.insert( TNodeNodeMap::value_type
10254 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10255 //nReplaceMap.insert( TNodeNodeMap::value_type
10256 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10257 for(int nn=0; nn<nbNodes-2; nn++) {
10258 nReplaceMap.insert( TNodeNodeMap::value_type
10259 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10263 //nReplaceMap.insert( TNodeNodeMap::value_type
10264 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10265 //nReplaceMap.insert( TNodeNodeMap::value_type
10266 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10267 for(int nn=0; nn<nbNodes-2; nn++) {
10268 nReplaceMap.insert( TNodeNodeMap::value_type
10269 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10274 // add other links of the faces to linkList
10275 // -----------------------------------------
10277 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10278 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10279 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10280 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10281 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10282 if ( !iter_isnew.second ) { // already in a set: no need to process
10283 linkIdSet.erase( iter_isnew.first );
10285 else // new in set == encountered for the first time: add
10287 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10288 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10289 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10290 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10291 linkList[0].push_back ( NLink( n1, n2 ));
10292 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10296 } // loop on link lists
10298 if ( aResult == SEW_OK &&
10299 ( linkIt[0] != linkList[0].end() ||
10300 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10301 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10302 " " << (faceSetPtr[1]->empty()));
10303 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10306 // ====================================================================
10307 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10308 // ====================================================================
10310 // delete temporary faces: they are in reverseElements of actual nodes
10311 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10312 // while ( tmpFaceIt->more() )
10313 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10314 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10315 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10316 // aMesh->RemoveElement(*tmpFaceIt);
10318 if ( aResult != SEW_OK)
10321 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10322 // loop on nodes replacement map
10323 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10324 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10325 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10326 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10327 nodeIDsToRemove.push_back( nToRemove->GetID() );
10328 // loop on elements sharing nToRemove
10329 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10330 while ( invElemIt->more() ) {
10331 const SMDS_MeshElement* e = invElemIt->next();
10332 // get a new suite of nodes: make replacement
10333 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10334 vector< const SMDS_MeshNode*> nodes( nbNodes );
10335 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10336 while ( nIt->more() ) {
10337 const SMDS_MeshNode* n =
10338 static_cast<const SMDS_MeshNode*>( nIt->next() );
10339 nnIt = nReplaceMap.find( n );
10340 if ( nnIt != nReplaceMap.end() ) {
10342 n = (*nnIt).second;
10346 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10347 // elemIDsToRemove.push_back( e->GetID() );
10351 SMDSAbs_ElementType etyp = e->GetType();
10352 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10355 myLastCreatedElems.Append(newElem);
10356 AddToSameGroups(newElem, e, aMesh);
10357 int aShapeId = e->getshapeId();
10360 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10363 aMesh->RemoveElement(e);
10368 Remove( nodeIDsToRemove, true );
10373 //================================================================================
10375 * \brief Find corresponding nodes in two sets of faces
10376 * \param theSide1 - first face set
10377 * \param theSide2 - second first face
10378 * \param theFirstNode1 - a boundary node of set 1
10379 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10380 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10381 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10382 * \param nReplaceMap - output map of corresponding nodes
10383 * \return bool - is a success or not
10385 //================================================================================
10388 //#define DEBUG_MATCHING_NODES
10391 SMESH_MeshEditor::Sew_Error
10392 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10393 set<const SMDS_MeshElement*>& theSide2,
10394 const SMDS_MeshNode* theFirstNode1,
10395 const SMDS_MeshNode* theFirstNode2,
10396 const SMDS_MeshNode* theSecondNode1,
10397 const SMDS_MeshNode* theSecondNode2,
10398 TNodeNodeMap & nReplaceMap)
10400 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10402 nReplaceMap.clear();
10403 if ( theFirstNode1 != theFirstNode2 )
10404 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10405 if ( theSecondNode1 != theSecondNode2 )
10406 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10408 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10409 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10411 list< NLink > linkList[2];
10412 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10413 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10415 // loop on links in linkList; find faces by links and append links
10416 // of the found faces to linkList
10417 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10418 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10419 NLink link[] = { *linkIt[0], *linkIt[1] };
10420 if ( linkSet.find( link[0] ) == linkSet.end() )
10423 // by links, find faces in the face sets,
10424 // and find indices of link nodes in the found faces;
10425 // in a face set, there is only one or no face sharing a link
10426 // ---------------------------------------------------------------
10428 const SMDS_MeshElement* face[] = { 0, 0 };
10429 list<const SMDS_MeshNode*> notLinkNodes[2];
10430 //bool reverse[] = { false, false }; // order of notLinkNodes
10432 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10434 const SMDS_MeshNode* n1 = link[iSide].first;
10435 const SMDS_MeshNode* n2 = link[iSide].second;
10436 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10437 set< const SMDS_MeshElement* > facesOfNode1;
10438 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10440 // during a loop of the first node, we find all faces around n1,
10441 // during a loop of the second node, we find one face sharing both n1 and n2
10442 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10443 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10444 while ( fIt->more() ) { // loop on faces sharing a node
10445 const SMDS_MeshElement* f = fIt->next();
10446 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10447 ! facesOfNode1.insert( f ).second ) // f encounters twice
10449 if ( face[ iSide ] ) {
10450 MESSAGE( "2 faces per link " );
10451 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10454 faceSet->erase( f );
10456 // get not link nodes
10457 int nbN = f->NbNodes();
10458 if ( f->IsQuadratic() )
10460 nbNodes[ iSide ] = nbN;
10461 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10462 int i1 = f->GetNodeIndex( n1 );
10463 int i2 = f->GetNodeIndex( n2 );
10464 int iEnd = nbN, iBeg = -1, iDelta = 1;
10465 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10467 std::swap( iEnd, iBeg ); iDelta = -1;
10472 if ( i == iEnd ) i = iBeg + iDelta;
10473 if ( i == i1 ) break;
10474 nodes.push_back ( f->GetNode( i ) );
10480 // check similarity of elements of the sides
10481 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10482 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10483 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10484 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10487 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10491 // set nodes to merge
10492 // -------------------
10494 if ( face[0] && face[1] ) {
10495 if ( nbNodes[0] != nbNodes[1] ) {
10496 MESSAGE("Diff nb of face nodes");
10497 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10499 #ifdef DEBUG_MATCHING_NODES
10500 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10501 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10502 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10504 int nbN = nbNodes[0];
10506 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10507 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10508 for ( int i = 0 ; i < nbN - 2; ++i ) {
10509 #ifdef DEBUG_MATCHING_NODES
10510 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10512 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10516 // add other links of the face 1 to linkList
10517 // -----------------------------------------
10519 const SMDS_MeshElement* f0 = face[0];
10520 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10521 for ( int i = 0; i < nbN; i++ )
10523 const SMDS_MeshNode* n2 = f0->GetNode( i );
10524 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10525 linkSet.insert( SMESH_TLink( n1, n2 ));
10526 if ( !iter_isnew.second ) { // already in a set: no need to process
10527 linkSet.erase( iter_isnew.first );
10529 else // new in set == encountered for the first time: add
10531 #ifdef DEBUG_MATCHING_NODES
10532 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10533 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10535 linkList[0].push_back ( NLink( n1, n2 ));
10536 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10541 } // loop on link lists
10546 //================================================================================
10548 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10549 \param theElems - the list of elements (edges or faces) to be replicated
10550 The nodes for duplication could be found from these elements
10551 \param theNodesNot - list of nodes to NOT replicate
10552 \param theAffectedElems - the list of elements (cells and edges) to which the
10553 replicated nodes should be associated to.
10554 \return TRUE if operation has been completed successfully, FALSE otherwise
10556 //================================================================================
10558 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10559 const TIDSortedElemSet& theNodesNot,
10560 const TIDSortedElemSet& theAffectedElems )
10562 myLastCreatedElems.Clear();
10563 myLastCreatedNodes.Clear();
10565 if ( theElems.size() == 0 )
10568 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10573 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10574 // duplicate elements and nodes
10575 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10576 // replce nodes by duplications
10577 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10581 //================================================================================
10583 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10584 \param theMeshDS - mesh instance
10585 \param theElems - the elements replicated or modified (nodes should be changed)
10586 \param theNodesNot - nodes to NOT replicate
10587 \param theNodeNodeMap - relation of old node to new created node
10588 \param theIsDoubleElem - flag os to replicate element or modify
10589 \return TRUE if operation has been completed successfully, FALSE otherwise
10591 //================================================================================
10593 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10594 const TIDSortedElemSet& theElems,
10595 const TIDSortedElemSet& theNodesNot,
10596 std::map< const SMDS_MeshNode*,
10597 const SMDS_MeshNode* >& theNodeNodeMap,
10598 const bool theIsDoubleElem )
10600 MESSAGE("doubleNodes");
10601 // iterate on through element and duplicate them (by nodes duplication)
10603 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10604 for ( ; elemItr != theElems.end(); ++elemItr )
10606 const SMDS_MeshElement* anElem = *elemItr;
10610 bool isDuplicate = false;
10611 // duplicate nodes to duplicate element
10612 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10613 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10615 while ( anIter->more() )
10618 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10619 SMDS_MeshNode* aNewNode = aCurrNode;
10620 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10621 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10622 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10625 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10626 theNodeNodeMap[ aCurrNode ] = aNewNode;
10627 myLastCreatedNodes.Append( aNewNode );
10629 isDuplicate |= (aCurrNode != aNewNode);
10630 newNodes[ ind++ ] = aNewNode;
10632 if ( !isDuplicate )
10635 if ( theIsDoubleElem )
10636 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10639 MESSAGE("ChangeElementNodes");
10640 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10647 //================================================================================
10649 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10650 \param theNodes - identifiers of nodes to be doubled
10651 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10652 nodes. If list of element identifiers is empty then nodes are doubled but
10653 they not assigned to elements
10654 \return TRUE if operation has been completed successfully, FALSE otherwise
10656 //================================================================================
10658 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10659 const std::list< int >& theListOfModifiedElems )
10661 MESSAGE("DoubleNodes");
10662 myLastCreatedElems.Clear();
10663 myLastCreatedNodes.Clear();
10665 if ( theListOfNodes.size() == 0 )
10668 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10672 // iterate through nodes and duplicate them
10674 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10676 std::list< int >::const_iterator aNodeIter;
10677 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10679 int aCurr = *aNodeIter;
10680 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10686 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10689 anOldNodeToNewNode[ aNode ] = aNewNode;
10690 myLastCreatedNodes.Append( aNewNode );
10694 // Create map of new nodes for modified elements
10696 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10698 std::list< int >::const_iterator anElemIter;
10699 for ( anElemIter = theListOfModifiedElems.begin();
10700 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10702 int aCurr = *anElemIter;
10703 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10707 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10709 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10711 while ( anIter->more() )
10713 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10714 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10716 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10717 aNodeArr[ ind++ ] = aNewNode;
10720 aNodeArr[ ind++ ] = aCurrNode;
10722 anElemToNodes[ anElem ] = aNodeArr;
10725 // Change nodes of elements
10727 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10728 anElemToNodesIter = anElemToNodes.begin();
10729 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10731 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10732 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10735 MESSAGE("ChangeElementNodes");
10736 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10745 //================================================================================
10747 \brief Check if element located inside shape
10748 \return TRUE if IN or ON shape, FALSE otherwise
10750 //================================================================================
10752 template<class Classifier>
10753 bool isInside(const SMDS_MeshElement* theElem,
10754 Classifier& theClassifier,
10755 const double theTol)
10757 gp_XYZ centerXYZ (0, 0, 0);
10758 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10759 while (aNodeItr->more())
10760 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10762 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10763 theClassifier.Perform(aPnt, theTol);
10764 TopAbs_State aState = theClassifier.State();
10765 return (aState == TopAbs_IN || aState == TopAbs_ON );
10768 //================================================================================
10770 * \brief Classifier of the 3D point on the TopoDS_Face
10771 * with interaface suitable for isInside()
10773 //================================================================================
10775 struct _FaceClassifier
10777 Extrema_ExtPS _extremum;
10778 BRepAdaptor_Surface _surface;
10779 TopAbs_State _state;
10781 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10783 _extremum.Initialize( _surface,
10784 _surface.FirstUParameter(), _surface.LastUParameter(),
10785 _surface.FirstVParameter(), _surface.LastVParameter(),
10786 _surface.Tolerance(), _surface.Tolerance() );
10788 void Perform(const gp_Pnt& aPnt, double theTol)
10790 _state = TopAbs_OUT;
10791 _extremum.Perform(aPnt);
10792 if ( _extremum.IsDone() )
10793 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10794 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10795 _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10797 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10800 TopAbs_State State() const
10807 //================================================================================
10809 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10810 \param theElems - group of of elements (edges or faces) to be replicated
10811 \param theNodesNot - group of nodes not to replicate
10812 \param theShape - shape to detect affected elements (element which geometric center
10813 located on or inside shape).
10814 The replicated nodes should be associated to affected elements.
10815 \return TRUE if operation has been completed successfully, FALSE otherwise
10817 //================================================================================
10819 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10820 const TIDSortedElemSet& theNodesNot,
10821 const TopoDS_Shape& theShape )
10823 if ( theShape.IsNull() )
10826 const double aTol = Precision::Confusion();
10827 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10828 auto_ptr<_FaceClassifier> aFaceClassifier;
10829 if ( theShape.ShapeType() == TopAbs_SOLID )
10831 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10832 bsc3d->PerformInfinitePoint(aTol);
10834 else if (theShape.ShapeType() == TopAbs_FACE )
10836 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10839 // iterates on indicated elements and get elements by back references from their nodes
10840 TIDSortedElemSet anAffected;
10841 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10842 for ( ; elemItr != theElems.end(); ++elemItr )
10844 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10848 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10849 while ( nodeItr->more() )
10851 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10852 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10854 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10855 while ( backElemItr->more() )
10857 const SMDS_MeshElement* curElem = backElemItr->next();
10858 if ( curElem && theElems.find(curElem) == theElems.end() &&
10860 isInside( curElem, *bsc3d, aTol ) :
10861 isInside( curElem, *aFaceClassifier, aTol )))
10862 anAffected.insert( curElem );
10866 return DoubleNodes( theElems, theNodesNot, anAffected );
10870 * \brief compute an oriented angle between two planes defined by four points.
10871 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10872 * @param p0 base of the rotation axe
10873 * @param p1 extremity of the rotation axe
10874 * @param g1 belongs to the first plane
10875 * @param g2 belongs to the second plane
10877 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10879 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10880 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10881 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10882 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10883 gp_Vec vref(p0, p1);
10886 gp_Vec n1 = vref.Crossed(v1);
10887 gp_Vec n2 = vref.Crossed(v2);
10888 return n2.AngleWithRef(n1, vref);
10892 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10893 * The list of groups must describe a partition of the mesh volumes.
10894 * The nodes of the internal faces at the boundaries of the groups are doubled.
10895 * In option, the internal faces are replaced by flat elements.
10896 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10897 * The flat elements are stored in groups of volumes.
10898 * @param theElems - list of groups of volumes, where a group of volume is a set of
10899 * SMDS_MeshElements sorted by Id.
10900 * @param createJointElems - if TRUE, create the elements
10901 * @return TRUE if operation has been completed successfully, FALSE otherwise
10903 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10904 bool createJointElems)
10906 MESSAGE("----------------------------------------------");
10907 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10908 MESSAGE("----------------------------------------------");
10910 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10911 meshDS->BuildDownWardConnectivity(true);
10913 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10915 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10916 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10917 // build the list of nodes shared by 2 or more domains, with their domain indexes
10919 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10920 std::map<int,int>celldom; // cell vtkId --> domain
10921 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10922 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10923 faceDomains.clear();
10925 cellDomains.clear();
10926 nodeDomains.clear();
10927 std::map<int,int> emptyMap;
10928 std::set<int> emptySet;
10931 for (int idom = 0; idom < theElems.size(); idom++)
10934 // --- build a map (face to duplicate --> volume to modify)
10935 // with all the faces shared by 2 domains (group of elements)
10936 // and corresponding volume of this domain, for each shared face.
10937 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10939 const TIDSortedElemSet& domain = theElems[idom];
10940 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10941 for (; elemItr != domain.end(); ++elemItr)
10943 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10946 int vtkId = anElem->getVtkId();
10947 int neighborsVtkIds[NBMAXNEIGHBORS];
10948 int downIds[NBMAXNEIGHBORS];
10949 unsigned char downTypes[NBMAXNEIGHBORS];
10950 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10951 for (int n = 0; n < nbNeighbors; n++)
10953 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10954 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10955 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10957 DownIdType face(downIds[n], downTypes[n]);
10958 if (!faceDomains.count(face))
10959 faceDomains[face] = emptyMap; // create an empty entry for face
10960 if (!faceDomains[face].count(idom))
10962 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10963 celldom[vtkId] = idom;
10970 //MESSAGE("Number of shared faces " << faceDomains.size());
10971 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10973 // --- explore the shared faces domain by domain,
10974 // explore the nodes of the face and see if they belong to a cell in the domain,
10975 // which has only a node or an edge on the border (not a shared face)
10977 for (int idomain = 0; idomain < theElems.size(); idomain++)
10979 const TIDSortedElemSet& domain = theElems[idomain];
10980 itface = faceDomains.begin();
10981 for (; itface != faceDomains.end(); ++itface)
10983 std::map<int, int> domvol = itface->second;
10984 if (!domvol.count(idomain))
10986 DownIdType face = itface->first;
10987 //MESSAGE(" --- face " << face.cellId);
10988 std::set<int> oldNodes;
10990 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10991 std::set<int>::iterator itn = oldNodes.begin();
10992 for (; itn != oldNodes.end(); ++itn)
10995 //MESSAGE(" node " << oldId);
10996 std::set<int> cells;
10998 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10999 for (int i=0; i<l.ncells; i++)
11001 int vtkId = l.cells[i];
11002 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11003 if (!domain.count(anElem))
11005 int vtkType = grid->GetCellType(vtkId);
11006 int downId = grid->CellIdToDownId(vtkId);
11009 MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11010 continue; // not OK at this stage of the algorithm:
11011 //no cells created after BuildDownWardConnectivity
11013 DownIdType aCell(downId, vtkType);
11014 if (celldom.count(vtkId))
11016 cellDomains[aCell][idomain] = vtkId;
11017 celldom[vtkId] = idomain;
11023 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11024 // for each shared face, get the nodes
11025 // for each node, for each domain of the face, create a clone of the node
11027 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11028 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11029 // the value is the ordered domain ids. (more than 4 domains not taken into account)
11031 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11032 std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11034 for (int idomain = 0; idomain < theElems.size(); idomain++)
11036 itface = faceDomains.begin();
11037 for (; itface != faceDomains.end(); ++itface)
11039 std::map<int, int> domvol = itface->second;
11040 if (!domvol.count(idomain))
11042 DownIdType face = itface->first;
11043 //MESSAGE(" --- face " << face.cellId);
11044 std::set<int> oldNodes;
11046 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11047 bool isMultipleDetected = false;
11048 std::set<int>::iterator itn = oldNodes.begin();
11049 for (; itn != oldNodes.end(); ++itn)
11052 //MESSAGE(" node " << oldId);
11053 if (!nodeDomains.count(oldId))
11054 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11055 if (nodeDomains[oldId].empty())
11056 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11057 std::map<int, int>::iterator itdom = domvol.begin();
11058 for (; itdom != domvol.end(); ++itdom)
11060 int idom = itdom->first;
11061 //MESSAGE(" domain " << idom);
11062 if (!nodeDomains[oldId].count(idom)) // --- node to clone
11064 if (nodeDomains[oldId].size() >= 2) // a multiple node
11066 vector<int> orderedDoms;
11067 //MESSAGE("multiple node " << oldId);
11068 isMultipleDetected =true;
11069 if (mutipleNodes.count(oldId))
11070 orderedDoms = mutipleNodes[oldId];
11073 map<int,int>::iterator it = nodeDomains[oldId].begin();
11074 for (; it != nodeDomains[oldId].end(); ++it)
11075 orderedDoms.push_back(it->first);
11077 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11078 //stringstream txt;
11079 //for (int i=0; i<orderedDoms.size(); i++)
11080 // txt << orderedDoms[i] << " ";
11081 //MESSAGE("orderedDoms " << txt.str());
11082 mutipleNodes[oldId] = orderedDoms;
11084 double *coords = grid->GetPoint(oldId);
11085 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11086 int newId = newNode->getVtkId();
11087 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11088 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11090 if (nodeDomains[oldId].size() >= 3)
11092 //MESSAGE("confirm multiple node " << oldId);
11093 isMultipleDetected =true;
11097 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11099 //MESSAGE("multiple Nodes detected on a shared face");
11100 int downId = itface->first.cellId;
11101 unsigned char cellType = itface->first.cellType;
11102 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11103 const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11104 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11105 for (int ie =0; ie < nbEdges; ie++)
11108 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11109 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11111 vector<int> vn0 = mutipleNodes[nodes[0]];
11112 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11113 sort( vn0.begin(), vn0.end() );
11114 sort( vn1.begin(), vn1.end() );
11117 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11118 double *coords = grid->GetPoint(nodes[0]);
11119 gp_Pnt p0(coords[0], coords[1], coords[2]);
11120 coords = grid->GetPoint(nodes[nbNodes - 1]);
11121 gp_Pnt p1(coords[0], coords[1], coords[2]);
11123 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11124 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11125 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11126 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11127 for (int id=0; id < vn0.size(); id++)
11129 int idom = vn0[id];
11130 for (int ivol=0; ivol<nbvol; ivol++)
11132 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11133 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11134 if (theElems[idom].count(elem))
11136 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11137 domvol[idom] = svol;
11138 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11140 vtkIdType npts = 0;
11141 vtkIdType* pts = 0;
11142 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11143 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11146 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11147 angleDom[idom] = 0;
11151 gp_Pnt g(values[0], values[1], values[2]);
11152 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11153 //MESSAGE(" angle=" << angleDom[idom]);
11159 map<double, int> sortedDom; // sort domains by angle
11160 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11161 sortedDom[ia->second] = ia->first;
11162 vector<int> vnodes;
11164 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11166 vdom.push_back(ib->second);
11167 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11169 for (int ino = 0; ino < nbNodes; ino++)
11170 vnodes.push_back(nodes[ino]);
11171 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11179 // --- iterate on shared faces (volumes to modify, face to extrude)
11180 // get node id's of the face (id SMDS = id VTK)
11181 // create flat element with old and new nodes if requested
11183 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11184 // (domain1 X domain2) = domain1 + MAXINT*domain2
11186 std::map<int, std::map<long,int> > nodeQuadDomains;
11187 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11189 if (createJointElems)
11191 itface = faceDomains.begin();
11192 for (; itface != faceDomains.end(); ++itface)
11194 DownIdType face = itface->first;
11195 std::set<int> oldNodes;
11196 std::set<int>::iterator itn;
11198 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11200 std::map<int, int> domvol = itface->second;
11201 std::map<int, int>::iterator itdom = domvol.begin();
11202 int dom1 = itdom->first;
11203 int vtkVolId = itdom->second;
11205 int dom2 = itdom->first;
11206 SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11208 stringstream grpname;
11211 grpname << dom1 << "_" << dom2;
11213 grpname << dom2 << "_" << dom1;
11215 string namegrp = grpname.str();
11216 if (!mapOfJunctionGroups.count(namegrp))
11217 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11218 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11220 sgrp->Add(vol->GetID());
11224 // --- create volumes on multiple domain intersection if requested
11225 // iterate on edgesMultiDomains
11227 if (createJointElems)
11229 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11230 for (; ite != edgesMultiDomains.end(); ++ite)
11232 vector<int> nodes = ite->first;
11233 vector<int> orderDom = ite->second;
11234 vector<vtkIdType> orderedNodes;
11235 if (nodes.size() == 2)
11237 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11238 for (int ino=0; ino < nodes.size(); ino++)
11239 if (orderDom.size() == 3)
11240 for (int idom = 0; idom <orderDom.size(); idom++)
11241 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11243 for (int idom = orderDom.size()-1; idom >=0; idom--)
11244 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11245 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11247 stringstream grpname;
11249 grpname << 0 << "_" << 0;
11251 string namegrp = grpname.str();
11252 if (!mapOfJunctionGroups.count(namegrp))
11253 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11254 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11256 sgrp->Add(vol->GetID());
11260 //MESSAGE("Quadratic multiple joints not implemented");
11261 // TODO quadratic nodes
11266 // --- list the explicit faces and edges of the mesh that need to be modified,
11267 // i.e. faces and edges built with one or more duplicated nodes.
11268 // associate these faces or edges to their corresponding domain.
11269 // only the first domain found is kept when a face or edge is shared
11271 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11272 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11273 faceOrEdgeDom.clear();
11276 for (int idomain = 0; idomain < theElems.size(); idomain++)
11278 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11279 for (; itnod != nodeDomains.end(); ++itnod)
11281 int oldId = itnod->first;
11282 //MESSAGE(" node " << oldId);
11283 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11284 for (int i = 0; i < l.ncells; i++)
11286 int vtkId = l.cells[i];
11287 int vtkType = grid->GetCellType(vtkId);
11288 int downId = grid->CellIdToDownId(vtkId);
11290 continue; // new cells: not to be modified
11291 DownIdType aCell(downId, vtkType);
11292 int volParents[1000];
11293 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11294 for (int j = 0; j < nbvol; j++)
11295 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11296 if (!feDom.count(vtkId))
11298 feDom[vtkId] = idomain;
11299 faceOrEdgeDom[aCell] = emptyMap;
11300 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11301 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11302 // << " type " << vtkType << " downId " << downId);
11308 // --- iterate on shared faces (volumes to modify, face to extrude)
11309 // get node id's of the face
11310 // replace old nodes by new nodes in volumes, and update inverse connectivity
11312 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11313 for (int m=0; m<3; m++)
11315 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11316 itface = (*amap).begin();
11317 for (; itface != (*amap).end(); ++itface)
11319 DownIdType face = itface->first;
11320 std::set<int> oldNodes;
11321 std::set<int>::iterator itn;
11323 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11324 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11325 std::map<int, int> localClonedNodeIds;
11327 std::map<int, int> domvol = itface->second;
11328 std::map<int, int>::iterator itdom = domvol.begin();
11329 for (; itdom != domvol.end(); ++itdom)
11331 int idom = itdom->first;
11332 int vtkVolId = itdom->second;
11333 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11334 localClonedNodeIds.clear();
11335 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11338 if (nodeDomains[oldId].count(idom))
11340 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11341 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11344 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11349 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11350 grid->BuildLinks();
11358 * \brief Double nodes on some external faces and create flat elements.
11359 * Flat elements are mainly used by some types of mechanic calculations.
11361 * Each group of the list must be constituted of faces.
11362 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11363 * @param theElems - list of groups of faces, where a group of faces is a set of
11364 * SMDS_MeshElements sorted by Id.
11365 * @return TRUE if operation has been completed successfully, FALSE otherwise
11367 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11369 MESSAGE("-------------------------------------------------");
11370 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11371 MESSAGE("-------------------------------------------------");
11373 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11375 // --- For each group of faces
11376 // duplicate the nodes, create a flat element based on the face
11377 // replace the nodes of the faces by their clones
11379 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11380 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11381 clonedNodes.clear();
11382 intermediateNodes.clear();
11383 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11384 mapOfJunctionGroups.clear();
11386 for (int idom = 0; idom < theElems.size(); idom++)
11388 const TIDSortedElemSet& domain = theElems[idom];
11389 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11390 for (; elemItr != domain.end(); ++elemItr)
11392 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11393 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11396 // MESSAGE("aFace=" << aFace->GetID());
11397 bool isQuad = aFace->IsQuadratic();
11398 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11400 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11402 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11403 while (nodeIt->more())
11405 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11406 bool isMedium = isQuad && (aFace->IsMediumNode(node));
11408 ln2.push_back(node);
11410 ln0.push_back(node);
11412 const SMDS_MeshNode* clone = 0;
11413 if (!clonedNodes.count(node))
11415 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11416 clonedNodes[node] = clone;
11419 clone = clonedNodes[node];
11422 ln3.push_back(clone);
11424 ln1.push_back(clone);
11426 const SMDS_MeshNode* inter = 0;
11427 if (isQuad && (!isMedium))
11429 if (!intermediateNodes.count(node))
11431 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11432 intermediateNodes[node] = inter;
11435 inter = intermediateNodes[node];
11436 ln4.push_back(inter);
11440 // --- extrude the face
11442 vector<const SMDS_MeshNode*> ln;
11443 SMDS_MeshVolume* vol = 0;
11444 vtkIdType aType = aFace->GetVtkType();
11448 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11449 // MESSAGE("vol prism " << vol->GetID());
11450 ln.push_back(ln1[0]);
11451 ln.push_back(ln1[1]);
11452 ln.push_back(ln1[2]);
11455 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11456 // MESSAGE("vol hexa " << vol->GetID());
11457 ln.push_back(ln1[0]);
11458 ln.push_back(ln1[1]);
11459 ln.push_back(ln1[2]);
11460 ln.push_back(ln1[3]);
11462 case VTK_QUADRATIC_TRIANGLE:
11463 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11464 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11465 // MESSAGE("vol quad prism " << vol->GetID());
11466 ln.push_back(ln1[0]);
11467 ln.push_back(ln1[1]);
11468 ln.push_back(ln1[2]);
11469 ln.push_back(ln3[0]);
11470 ln.push_back(ln3[1]);
11471 ln.push_back(ln3[2]);
11473 case VTK_QUADRATIC_QUAD:
11474 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11475 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11476 // ln4[0], ln4[1], ln4[2], ln4[3]);
11477 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11478 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11479 ln4[0], ln4[1], ln4[2], ln4[3]);
11480 // MESSAGE("vol quad hexa " << vol->GetID());
11481 ln.push_back(ln1[0]);
11482 ln.push_back(ln1[1]);
11483 ln.push_back(ln1[2]);
11484 ln.push_back(ln1[3]);
11485 ln.push_back(ln3[0]);
11486 ln.push_back(ln3[1]);
11487 ln.push_back(ln3[2]);
11488 ln.push_back(ln3[3]);
11498 stringstream grpname;
11502 string namegrp = grpname.str();
11503 if (!mapOfJunctionGroups.count(namegrp))
11504 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11505 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11507 sgrp->Add(vol->GetID());
11510 // --- modify the face
11512 aFace->ChangeNodes(&ln[0], ln.size());
11518 //================================================================================
11520 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11521 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11522 * \return TRUE if operation has been completed successfully, FALSE otherwise
11524 //================================================================================
11526 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11528 // iterates on volume elements and detect all free faces on them
11529 SMESHDS_Mesh* aMesh = GetMeshDS();
11532 //bool res = false;
11533 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11534 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11537 const SMDS_MeshVolume* volume = vIt->next();
11538 SMDS_VolumeTool vTool( volume );
11539 vTool.SetExternalNormal();
11540 const bool isPoly = volume->IsPoly();
11541 const bool isQuad = volume->IsQuadratic();
11542 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11544 if (!vTool.IsFreeFace(iface))
11547 vector<const SMDS_MeshNode *> nodes;
11548 int nbFaceNodes = vTool.NbFaceNodes(iface);
11549 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11551 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11552 nodes.push_back(faceNodes[inode]);
11554 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11555 nodes.push_back(faceNodes[inode]);
11557 // add new face based on volume nodes
11558 if (aMesh->FindFace( nodes ) ) {
11560 continue; // face already exsist
11562 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11566 return ( nbFree==(nbExisted+nbCreated) );
11571 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11573 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11575 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11578 //================================================================================
11580 * \brief Creates missing boundary elements
11581 * \param elements - elements whose boundary is to be checked
11582 * \param dimension - defines type of boundary elements to create
11583 * \param group - a group to store created boundary elements in
11584 * \param targetMesh - a mesh to store created boundary elements in
11585 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11586 * \param toCopyExistingBoundary - if true, not only new but also pre-existing
11587 * boundary elements will be copied into the targetMesh
11588 * \param toAddExistingBondary - if true, not only new but also pre-existing
11589 * boundary elements will be added into the new group
11590 * \param aroundElements - if true, elements will be created on boundary of given
11591 * elements else, on boundary of the whole mesh.
11592 * \return nb of added boundary elements
11594 //================================================================================
11596 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11597 Bnd_Dimension dimension,
11598 SMESH_Group* group/*=0*/,
11599 SMESH_Mesh* targetMesh/*=0*/,
11600 bool toCopyElements/*=false*/,
11601 bool toCopyExistingBoundary/*=false*/,
11602 bool toAddExistingBondary/*= false*/,
11603 bool aroundElements/*= false*/)
11605 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11606 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11607 // hope that all elements are of the same type, do not check them all
11608 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11609 throw SALOME_Exception(LOCALIZED("wrong element type"));
11612 toCopyElements = toCopyExistingBoundary = false;
11614 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11615 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11616 int nbAddedBnd = 0;
11618 // editor adding present bnd elements and optionally holding elements to add to the group
11619 SMESH_MeshEditor* presentEditor;
11620 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11621 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11623 SMDS_VolumeTool vTool;
11624 TIDSortedElemSet avoidSet;
11625 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11628 typedef vector<const SMDS_MeshNode*> TConnectivity;
11630 SMDS_ElemIteratorPtr eIt;
11631 if (elements.empty())
11632 eIt = aMesh->elementsIterator(elemType);
11634 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11636 while (eIt->more())
11638 const SMDS_MeshElement* elem = eIt->next();
11639 const int iQuad = elem->IsQuadratic();
11641 // ------------------------------------------------------------------------------------
11642 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11643 // ------------------------------------------------------------------------------------
11644 vector<const SMDS_MeshElement*> presentBndElems;
11645 vector<TConnectivity> missingBndElems;
11646 TConnectivity nodes;
11647 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11649 vTool.SetExternalNormal();
11650 const SMDS_MeshElement* otherVol = 0;
11651 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11653 if ( !vTool.IsFreeFace(iface, &otherVol) &&
11654 ( !aroundElements || elements.count( otherVol )))
11656 const int nbFaceNodes = vTool.NbFaceNodes(iface);
11657 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11658 if ( missType == SMDSAbs_Edge ) // boundary edges
11660 nodes.resize( 2+iQuad );
11661 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11663 for ( int j = 0; j < nodes.size(); ++j )
11665 if ( const SMDS_MeshElement* edge =
11666 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11667 presentBndElems.push_back( edge );
11669 missingBndElems.push_back( nodes );
11672 else // boundary face
11675 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11676 nodes.push_back( nn[inode] );
11678 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11679 nodes.push_back( nn[inode] );
11681 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11682 presentBndElems.push_back( f );
11684 missingBndElems.push_back( nodes );
11686 if ( targetMesh != myMesh )
11688 // add 1D elements on face boundary to be added to a new mesh
11689 const SMDS_MeshElement* edge;
11690 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11693 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11695 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11696 if ( edge && avoidSet.insert( edge ).second )
11697 presentBndElems.push_back( edge );
11703 else // elem is a face ------------------------------------------
11705 avoidSet.clear(), avoidSet.insert( elem );
11706 int nbNodes = elem->NbCornerNodes();
11707 nodes.resize( 2 /*+ iQuad*/);
11708 for ( int i = 0; i < nbNodes; i++ )
11710 nodes[0] = elem->GetNode(i);
11711 nodes[1] = elem->GetNode((i+1)%nbNodes);
11712 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11713 continue; // not free link
11716 //nodes[2] = elem->GetNode( i + nbNodes );
11717 if ( const SMDS_MeshElement* edge =
11718 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11719 presentBndElems.push_back( edge );
11721 missingBndElems.push_back( nodes );
11725 // ---------------------------------
11726 // 2. Add missing boundary elements
11727 // ---------------------------------
11728 if ( targetMesh != myMesh )
11729 // instead of making a map of nodes in this mesh and targetMesh,
11730 // we create nodes with same IDs.
11731 for ( int i = 0; i < missingBndElems.size(); ++i )
11733 TConnectivity& srcNodes = missingBndElems[i];
11734 TConnectivity nodes( srcNodes.size() );
11735 for ( inode = 0; inode < nodes.size(); ++inode )
11736 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11737 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11739 /*noMedium=*/true))
11741 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11745 for ( int i = 0; i < missingBndElems.size(); ++i )
11747 TConnectivity& nodes = missingBndElems[i];
11748 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11750 /*noMedium=*/true))
11752 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11756 // ----------------------------------
11757 // 3. Copy present boundary elements
11758 // ----------------------------------
11759 if ( toCopyExistingBoundary )
11760 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11762 const SMDS_MeshElement* e = presentBndElems[i];
11763 TConnectivity nodes( e->NbNodes() );
11764 for ( inode = 0; inode < nodes.size(); ++inode )
11765 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11766 presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11768 else // store present elements to add them to a group
11769 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11771 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11774 } // loop on given elements
11776 // ---------------------------------------------
11777 // 4. Fill group with boundary elements
11778 // ---------------------------------------------
11781 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11782 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11783 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11785 tgtEditor.myLastCreatedElems.Clear();
11786 tgtEditor2.myLastCreatedElems.Clear();
11788 // -----------------------
11789 // 5. Copy given elements
11790 // -----------------------
11791 if ( toCopyElements && targetMesh != myMesh )
11793 if (elements.empty())
11794 eIt = aMesh->elementsIterator(elemType);
11796 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11797 while (eIt->more())
11799 const SMDS_MeshElement* elem = eIt->next();
11800 TConnectivity nodes( elem->NbNodes() );
11801 for ( inode = 0; inode < nodes.size(); ++inode )
11802 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11803 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11805 tgtEditor.myLastCreatedElems.Clear();