1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
29 #include "SMESH_MeshEditor.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
53 #include "utilities.h"
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101 using namespace SMESH::Controls;
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
108 //=======================================================================
109 //function : SMESH_MeshEditor
111 //=======================================================================
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114 :myMesh( theMesh ) // theMesh may be NULL
118 //=======================================================================
122 //=======================================================================
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126 const SMDSAbs_ElementType type,
130 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131 SMDS_MeshElement* e = 0;
132 int nbnode = node.size();
133 SMESHDS_Mesh* mesh = GetMeshDS();
135 case SMDSAbs_0DElement:
137 if ( ID >= 0 ) e = mesh->Add0DElementWithID(node[0], ID);
138 else e = mesh->Add0DElement (node[0] );
143 if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
144 else e = mesh->AddEdge (node[0], node[1] );
146 else if ( nbnode == 3 ) {
147 if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
148 else e = mesh->AddEdge (node[0], node[1], node[2] );
154 if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
155 else e = mesh->AddFace (node[0], node[1], node[2] );
157 else if (nbnode == 4) {
158 if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
159 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
161 else if (nbnode == 6) {
162 if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
163 node[4], node[5], ID);
164 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
167 else if (nbnode == 8) {
168 if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
169 node[4], node[5], node[6], node[7], ID);
170 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
171 node[4], node[5], node[6], node[7] );
174 if ( ID >= 0 ) e = mesh->AddPolygonalFaceWithID(node, ID);
175 else e = mesh->AddPolygonalFace (node );
181 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
182 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
184 else if (nbnode == 5) {
185 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
187 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
190 else if (nbnode == 6) {
191 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192 node[4], node[5], ID);
193 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
196 else if (nbnode == 8) {
197 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
198 node[4], node[5], node[6], node[7], ID);
199 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
200 node[4], node[5], node[6], node[7] );
202 else if (nbnode == 10) {
203 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
204 node[4], node[5], node[6], node[7],
205 node[8], node[9], ID);
206 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
207 node[4], node[5], node[6], node[7],
210 else if (nbnode == 13) {
211 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212 node[4], node[5], node[6], node[7],
213 node[8], node[9], node[10],node[11],
215 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
216 node[4], node[5], node[6], node[7],
217 node[8], node[9], node[10],node[11],
220 else if (nbnode == 15) {
221 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
222 node[4], node[5], node[6], node[7],
223 node[8], node[9], node[10],node[11],
224 node[12],node[13],node[14],ID);
225 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
226 node[4], node[5], node[6], node[7],
227 node[8], node[9], node[10],node[11],
228 node[12],node[13],node[14] );
230 else if (nbnode == 20) {
231 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
232 node[4], node[5], node[6], node[7],
233 node[8], node[9], node[10],node[11],
234 node[12],node[13],node[14],node[15],
235 node[16],node[17],node[18],node[19],ID);
236 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
237 node[4], node[5], node[6], node[7],
238 node[8], node[9], node[10],node[11],
239 node[12],node[13],node[14],node[15],
240 node[16],node[17],node[18],node[19] );
244 if ( e ) myLastCreatedElems.Append( e );
248 //=======================================================================
252 //=======================================================================
254 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
255 const SMDSAbs_ElementType type,
259 vector<const SMDS_MeshNode*> nodes;
260 nodes.reserve( nodeIDs.size() );
261 vector<int>::const_iterator id = nodeIDs.begin();
262 while ( id != nodeIDs.end() ) {
263 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
264 nodes.push_back( node );
268 return AddElement( nodes, type, isPoly, ID );
271 //=======================================================================
273 //purpose : Remove a node or an element.
274 // Modify a compute state of sub-meshes which become empty
275 //=======================================================================
277 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
280 myLastCreatedElems.Clear();
281 myLastCreatedNodes.Clear();
283 SMESHDS_Mesh* aMesh = GetMeshDS();
284 set< SMESH_subMesh *> smmap;
287 list<int>::const_iterator it = theIDs.begin();
288 for ( ; it != theIDs.end(); it++ ) {
289 const SMDS_MeshElement * elem;
291 elem = aMesh->FindNode( *it );
293 elem = aMesh->FindElement( *it );
297 // Notify VERTEX sub-meshes about modification
299 const SMDS_MeshNode* node = cast2Node( elem );
300 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
301 if ( int aShapeID = node->getshapeId() )
302 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
305 // Find sub-meshes to notify about modification
306 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
307 // while ( nodeIt->more() ) {
308 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
309 // const SMDS_PositionPtr& aPosition = node->GetPosition();
310 // if ( aPosition.get() ) {
311 // if ( int aShapeID = aPosition->GetShapeId() ) {
312 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
313 // smmap.insert( sm );
320 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
322 aMesh->RemoveElement( elem );
326 // Notify sub-meshes about modification
327 if ( !smmap.empty() ) {
328 set< SMESH_subMesh *>::iterator smIt;
329 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
330 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
333 // // Check if the whole mesh becomes empty
334 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
335 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
340 //=======================================================================
341 //function : FindShape
342 //purpose : Return an index of the shape theElem is on
343 // or zero if a shape not found
344 //=======================================================================
346 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
348 myLastCreatedElems.Clear();
349 myLastCreatedNodes.Clear();
351 SMESHDS_Mesh * aMesh = GetMeshDS();
352 if ( aMesh->ShapeToMesh().IsNull() )
355 if ( theElem->GetType() == SMDSAbs_Node )
357 int aShapeID = theElem->getshapeId();
364 TopoDS_Shape aShape; // the shape a node is on
365 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
366 while ( nodeIt->more() ) {
367 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
368 int aShapeID = node->getshapeId();
370 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
372 if ( sm->Contains( theElem ))
374 if ( aShape.IsNull() )
375 aShape = aMesh->IndexToShape( aShapeID );
378 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
383 // None of nodes is on a proper shape,
384 // find the shape among ancestors of aShape on which a node is
385 if ( aShape.IsNull() ) {
386 //MESSAGE ("::FindShape() - NONE node is on shape")
389 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
390 for ( ; ancIt.More(); ancIt.Next() ) {
391 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
392 if ( sm && sm->Contains( theElem ))
393 return aMesh->ShapeToIndex( ancIt.Value() );
396 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
400 //=======================================================================
401 //function : IsMedium
403 //=======================================================================
405 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
406 const SMDSAbs_ElementType typeToCheck)
408 bool isMedium = false;
409 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
410 while (it->more() && !isMedium ) {
411 const SMDS_MeshElement* elem = it->next();
412 isMedium = elem->IsMediumNode(node);
417 //=======================================================================
418 //function : ShiftNodesQuadTria
420 // Shift nodes in the array corresponded to quadratic triangle
421 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
422 //=======================================================================
423 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
425 const SMDS_MeshNode* nd1 = aNodes[0];
426 aNodes[0] = aNodes[1];
427 aNodes[1] = aNodes[2];
429 const SMDS_MeshNode* nd2 = aNodes[3];
430 aNodes[3] = aNodes[4];
431 aNodes[4] = aNodes[5];
435 //=======================================================================
436 //function : GetNodesFromTwoTria
438 // Shift nodes in the array corresponded to quadratic triangle
439 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
440 //=======================================================================
441 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
442 const SMDS_MeshElement * theTria2,
443 const SMDS_MeshNode* N1[],
444 const SMDS_MeshNode* N2[])
446 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
449 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
452 if(it->more()) return false;
453 it = theTria2->nodesIterator();
456 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
459 if(it->more()) return false;
461 int sames[3] = {-1,-1,-1};
473 if(nbsames!=2) return false;
475 ShiftNodesQuadTria(N1);
477 ShiftNodesQuadTria(N1);
480 i = sames[0] + sames[1] + sames[2];
482 ShiftNodesQuadTria(N2);
484 // now we receive following N1 and N2 (using numeration as above image)
485 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
486 // i.e. first nodes from both arrays determ new diagonal
490 //=======================================================================
491 //function : InverseDiag
492 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
493 // but having other common link.
494 // Return False if args are improper
495 //=======================================================================
497 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
498 const SMDS_MeshElement * theTria2 )
500 MESSAGE("InverseDiag");
501 myLastCreatedElems.Clear();
502 myLastCreatedNodes.Clear();
504 if (!theTria1 || !theTria2)
507 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
508 if (!F1) return false;
509 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
510 if (!F2) return false;
511 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
512 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
514 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
515 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
519 // put nodes in array and find out indices of the same ones
520 const SMDS_MeshNode* aNodes [6];
521 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
523 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
524 while ( it->more() ) {
525 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
527 if ( i > 2 ) // theTria2
528 // find same node of theTria1
529 for ( int j = 0; j < 3; j++ )
530 if ( aNodes[ i ] == aNodes[ j ]) {
539 return false; // theTria1 is not a triangle
540 it = theTria2->nodesIterator();
542 if ( i == 6 && it->more() )
543 return false; // theTria2 is not a triangle
546 // find indices of 1,2 and of A,B in theTria1
547 int iA = 0, iB = 0, i1 = 0, i2 = 0;
548 for ( i = 0; i < 6; i++ ) {
549 if ( sameInd [ i ] == 0 ) {
558 // nodes 1 and 2 should not be the same
559 if ( aNodes[ i1 ] == aNodes[ i2 ] )
563 aNodes[ iA ] = aNodes[ i2 ];
565 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
567 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
568 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
572 } // end if(F1 && F2)
574 // check case of quadratic faces
575 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
577 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
581 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
582 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
590 const SMDS_MeshNode* N1 [6];
591 const SMDS_MeshNode* N2 [6];
592 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
594 // now we receive following N1 and N2 (using numeration as above image)
595 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
596 // i.e. first nodes from both arrays determ new diagonal
598 const SMDS_MeshNode* N1new [6];
599 const SMDS_MeshNode* N2new [6];
612 // replaces nodes in faces
613 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
614 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
619 //=======================================================================
620 //function : findTriangles
621 //purpose : find triangles sharing theNode1-theNode2 link
622 //=======================================================================
624 static bool findTriangles(const SMDS_MeshNode * theNode1,
625 const SMDS_MeshNode * theNode2,
626 const SMDS_MeshElement*& theTria1,
627 const SMDS_MeshElement*& theTria2)
629 if ( !theNode1 || !theNode2 ) return false;
631 theTria1 = theTria2 = 0;
633 set< const SMDS_MeshElement* > emap;
634 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
636 const SMDS_MeshElement* elem = it->next();
637 if ( elem->NbNodes() == 3 )
640 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
642 const SMDS_MeshElement* elem = it->next();
643 if ( emap.find( elem ) != emap.end() ) {
645 // theTria1 must be element with minimum ID
646 if( theTria1->GetID() < elem->GetID() ) {
660 return ( theTria1 && theTria2 );
663 //=======================================================================
664 //function : InverseDiag
665 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
666 // with ones built on the same 4 nodes but having other common link.
667 // Return false if proper faces not found
668 //=======================================================================
670 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
671 const SMDS_MeshNode * theNode2)
673 myLastCreatedElems.Clear();
674 myLastCreatedNodes.Clear();
676 MESSAGE( "::InverseDiag()" );
678 const SMDS_MeshElement *tr1, *tr2;
679 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
682 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
683 if (!F1) return false;
684 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
685 if (!F2) return false;
686 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
687 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
689 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
690 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
694 // put nodes in array
695 // and find indices of 1,2 and of A in tr1 and of B in tr2
696 int i, iA1 = 0, i1 = 0;
697 const SMDS_MeshNode* aNodes1 [3];
698 SMDS_ElemIteratorPtr it;
699 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
700 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
701 if ( aNodes1[ i ] == theNode1 )
702 iA1 = i; // node A in tr1
703 else if ( aNodes1[ i ] != theNode2 )
707 const SMDS_MeshNode* aNodes2 [3];
708 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
709 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
710 if ( aNodes2[ i ] == theNode2 )
711 iB2 = i; // node B in tr2
712 else if ( aNodes2[ i ] != theNode1 )
716 // nodes 1 and 2 should not be the same
717 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
721 aNodes1[ iA1 ] = aNodes2[ i2 ];
723 aNodes2[ iB2 ] = aNodes1[ i1 ];
725 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
726 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
731 // check case of quadratic faces
732 return InverseDiag(tr1,tr2);
735 //=======================================================================
736 //function : getQuadrangleNodes
737 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
738 // fusion of triangles tr1 and tr2 having shared link on
739 // theNode1 and theNode2
740 //=======================================================================
742 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
743 const SMDS_MeshNode * theNode1,
744 const SMDS_MeshNode * theNode2,
745 const SMDS_MeshElement * tr1,
746 const SMDS_MeshElement * tr2 )
748 if( tr1->NbNodes() != tr2->NbNodes() )
750 // find the 4-th node to insert into tr1
751 const SMDS_MeshNode* n4 = 0;
752 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
754 while ( !n4 && i<3 ) {
755 const SMDS_MeshNode * n = cast2Node( it->next() );
757 bool isDiag = ( n == theNode1 || n == theNode2 );
761 // Make an array of nodes to be in a quadrangle
762 int iNode = 0, iFirstDiag = -1;
763 it = tr1->nodesIterator();
766 const SMDS_MeshNode * n = cast2Node( it->next() );
768 bool isDiag = ( n == theNode1 || n == theNode2 );
770 if ( iFirstDiag < 0 )
772 else if ( iNode - iFirstDiag == 1 )
773 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
775 else if ( n == n4 ) {
776 return false; // tr1 and tr2 should not have all the same nodes
778 theQuadNodes[ iNode++ ] = n;
780 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
781 theQuadNodes[ iNode ] = n4;
786 //=======================================================================
787 //function : DeleteDiag
788 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
789 // with a quadrangle built on the same 4 nodes.
790 // Return false if proper faces not found
791 //=======================================================================
793 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
794 const SMDS_MeshNode * theNode2)
796 myLastCreatedElems.Clear();
797 myLastCreatedNodes.Clear();
799 MESSAGE( "::DeleteDiag()" );
801 const SMDS_MeshElement *tr1, *tr2;
802 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
805 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
806 if (!F1) return false;
807 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
808 if (!F2) return false;
809 SMESHDS_Mesh * aMesh = GetMeshDS();
811 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
812 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
814 const SMDS_MeshNode* aNodes [ 4 ];
815 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
818 const SMDS_MeshElement* newElem = 0;
819 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
820 myLastCreatedElems.Append(newElem);
821 AddToSameGroups( newElem, tr1, aMesh );
822 int aShapeId = tr1->getshapeId();
825 aMesh->SetMeshElementOnShape( newElem, aShapeId );
827 aMesh->RemoveElement( tr1 );
828 aMesh->RemoveElement( tr2 );
833 // check case of quadratic faces
834 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
836 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
840 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
841 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
849 const SMDS_MeshNode* N1 [6];
850 const SMDS_MeshNode* N2 [6];
851 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
853 // now we receive following N1 and N2 (using numeration as above image)
854 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
855 // i.e. first nodes from both arrays determ new diagonal
857 const SMDS_MeshNode* aNodes[8];
867 const SMDS_MeshElement* newElem = 0;
868 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
869 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
870 myLastCreatedElems.Append(newElem);
871 AddToSameGroups( newElem, tr1, aMesh );
872 int aShapeId = tr1->getshapeId();
875 aMesh->SetMeshElementOnShape( newElem, aShapeId );
877 aMesh->RemoveElement( tr1 );
878 aMesh->RemoveElement( tr2 );
880 // remove middle node (9)
881 GetMeshDS()->RemoveNode( N1[4] );
886 //=======================================================================
887 //function : Reorient
888 //purpose : Reverse theElement orientation
889 //=======================================================================
891 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
894 myLastCreatedElems.Clear();
895 myLastCreatedNodes.Clear();
899 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
900 if ( !it || !it->more() )
903 switch ( theElem->GetType() ) {
907 if(!theElem->IsQuadratic()) {
908 int i = theElem->NbNodes();
909 vector<const SMDS_MeshNode*> aNodes( i );
911 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
912 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
915 // quadratic elements
916 if(theElem->GetType()==SMDSAbs_Edge) {
917 vector<const SMDS_MeshNode*> aNodes(3);
918 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
919 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
920 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
921 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
924 int nbn = theElem->NbNodes();
925 vector<const SMDS_MeshNode*> aNodes(nbn);
926 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
928 for(; i<nbn/2; i++) {
929 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
931 for(i=0; i<nbn/2; i++) {
932 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
934 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
938 case SMDSAbs_Volume: {
939 if (theElem->IsPoly()) {
940 // TODO reorient vtk polyhedron
941 MESSAGE("reorient vtk polyhedron ?");
942 const SMDS_VtkVolume* aPolyedre =
943 dynamic_cast<const SMDS_VtkVolume*>( theElem );
945 MESSAGE("Warning: bad volumic element");
949 int nbFaces = aPolyedre->NbFaces();
950 vector<const SMDS_MeshNode *> poly_nodes;
951 vector<int> quantities (nbFaces);
953 // reverse each face of the polyedre
954 for (int iface = 1; iface <= nbFaces; iface++) {
955 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
956 quantities[iface - 1] = nbFaceNodes;
958 for (inode = nbFaceNodes; inode >= 1; inode--) {
959 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
960 poly_nodes.push_back(curNode);
964 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
968 SMDS_VolumeTool vTool;
969 if ( !vTool.Set( theElem ))
972 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
973 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
982 //=======================================================================
983 //function : getBadRate
985 //=======================================================================
987 static double getBadRate (const SMDS_MeshElement* theElem,
988 SMESH::Controls::NumericalFunctorPtr& theCrit)
990 SMESH::Controls::TSequenceOfXYZ P;
991 if ( !theElem || !theCrit->GetPoints( theElem, P ))
993 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
994 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
997 //=======================================================================
998 //function : QuadToTri
999 //purpose : Cut quadrangles into triangles.
1000 // theCrit is used to select a diagonal to cut
1001 //=======================================================================
1003 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1004 SMESH::Controls::NumericalFunctorPtr theCrit)
1006 myLastCreatedElems.Clear();
1007 myLastCreatedNodes.Clear();
1009 MESSAGE( "::QuadToTri()" );
1011 if ( !theCrit.get() )
1014 SMESHDS_Mesh * aMesh = GetMeshDS();
1016 Handle(Geom_Surface) surface;
1017 SMESH_MesherHelper helper( *GetMesh() );
1019 TIDSortedElemSet::iterator itElem;
1020 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1021 const SMDS_MeshElement* elem = *itElem;
1022 if ( !elem || elem->GetType() != SMDSAbs_Face )
1024 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1027 // retrieve element nodes
1028 const SMDS_MeshNode* aNodes [8];
1029 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1031 while ( itN->more() )
1032 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1034 // compare two sets of possible triangles
1035 double aBadRate1, aBadRate2; // to what extent a set is bad
1036 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1037 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1038 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1040 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1041 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1042 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1044 int aShapeId = FindShape( elem );
1045 const SMDS_MeshElement* newElem1 = 0;
1046 const SMDS_MeshElement* newElem2 = 0;
1048 if( !elem->IsQuadratic() ) {
1050 // split liner quadrangle
1051 if ( aBadRate1 <= aBadRate2 ) {
1052 // tr1 + tr2 is better
1053 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1054 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1057 // tr3 + tr4 is better
1058 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1059 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1064 // split quadratic quadrangle
1066 // get surface elem is on
1067 if ( aShapeId != helper.GetSubShapeID() ) {
1071 shape = aMesh->IndexToShape( aShapeId );
1072 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1073 TopoDS_Face face = TopoDS::Face( shape );
1074 surface = BRep_Tool::Surface( face );
1075 if ( !surface.IsNull() )
1076 helper.SetSubShape( shape );
1080 const SMDS_MeshNode* aNodes [8];
1081 const SMDS_MeshNode* inFaceNode = 0;
1082 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1084 while ( itN->more() ) {
1085 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1086 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1087 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1089 inFaceNode = aNodes[ i-1 ];
1092 // find middle point for (0,1,2,3)
1093 // and create a node in this point;
1095 if ( surface.IsNull() ) {
1097 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1101 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1104 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1106 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1108 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1109 myLastCreatedNodes.Append(newN);
1111 // create a new element
1112 const SMDS_MeshNode* N[6];
1113 if ( aBadRate1 <= aBadRate2 ) {
1120 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1121 aNodes[6], aNodes[7], newN );
1122 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1123 newN, aNodes[4], aNodes[5] );
1132 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1133 aNodes[7], aNodes[4], newN );
1134 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1135 newN, aNodes[5], aNodes[6] );
1139 // care of a new element
1141 myLastCreatedElems.Append(newElem1);
1142 myLastCreatedElems.Append(newElem2);
1143 AddToSameGroups( newElem1, elem, aMesh );
1144 AddToSameGroups( newElem2, elem, aMesh );
1146 // put a new triangle on the same shape
1149 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1150 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1152 aMesh->RemoveElement( elem );
1157 //=======================================================================
1158 //function : BestSplit
1159 //purpose : Find better diagonal for cutting.
1160 //=======================================================================
1162 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1163 SMESH::Controls::NumericalFunctorPtr theCrit)
1165 myLastCreatedElems.Clear();
1166 myLastCreatedNodes.Clear();
1171 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1174 if( theQuad->NbNodes()==4 ||
1175 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1177 // retrieve element nodes
1178 const SMDS_MeshNode* aNodes [4];
1179 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1181 //while (itN->more())
1183 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1185 // compare two sets of possible triangles
1186 double aBadRate1, aBadRate2; // to what extent a set is bad
1187 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1188 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1189 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1191 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1192 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1193 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1195 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1196 return 1; // diagonal 1-3
1198 return 2; // diagonal 2-4
1205 // Methods of splitting volumes into tetra
1207 const int theHexTo5_1[5*4+1] =
1209 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1211 const int theHexTo5_2[5*4+1] =
1213 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1215 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1217 const int theHexTo6_1[6*4+1] =
1219 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
1221 const int theHexTo6_2[6*4+1] =
1223 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
1225 const int theHexTo6_3[6*4+1] =
1227 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
1229 const int theHexTo6_4[6*4+1] =
1231 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
1233 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1235 const int thePyraTo2_1[2*4+1] =
1237 0, 1, 2, 4, 0, 2, 3, 4, -1
1239 const int thePyraTo2_2[2*4+1] =
1241 1, 2, 3, 4, 1, 3, 0, 4, -1
1243 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1245 const int thePentaTo3_1[3*4+1] =
1247 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1249 const int thePentaTo3_2[3*4+1] =
1251 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1253 const int thePentaTo3_3[3*4+1] =
1255 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1257 const int thePentaTo3_4[3*4+1] =
1259 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1261 const int thePentaTo3_5[3*4+1] =
1263 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1265 const int thePentaTo3_6[3*4+1] =
1267 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1269 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1270 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1272 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1275 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1276 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1277 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1282 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1283 bool _baryNode; //!< additional node is to be created at cell barycenter
1284 bool _ownConn; //!< to delete _connectivity in destructor
1285 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1287 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1288 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1289 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1290 bool hasFacet( const TTriangleFacet& facet ) const
1292 const int* tetConn = _connectivity;
1293 for ( ; tetConn[0] >= 0; tetConn += 4 )
1294 if (( facet.contains( tetConn[0] ) +
1295 facet.contains( tetConn[1] ) +
1296 facet.contains( tetConn[2] ) +
1297 facet.contains( tetConn[3] )) == 3 )
1303 //=======================================================================
1305 * \brief return TSplitMethod for the given element
1307 //=======================================================================
1309 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1311 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1313 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1314 // an edge and a face barycenter; tertaherdons are based on triangles and
1315 // a volume barycenter
1316 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1318 // Find out how adjacent volumes are split
1320 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1321 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1322 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1324 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1325 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1326 if ( nbNodes < 4 ) continue;
1328 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1329 const int* nInd = vol.GetFaceNodesIndices( iF );
1332 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1333 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1334 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1335 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1339 int iCom = 0; // common node of triangle faces to split into
1340 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1342 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1343 nInd[ iQ * ( (iCom+1)%nbNodes )],
1344 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1345 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1346 nInd[ iQ * ( (iCom+2)%nbNodes )],
1347 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1348 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1350 triaSplits.push_back( t012 );
1351 triaSplits.push_back( t023 );
1356 if ( !triaSplits.empty() )
1357 hasAdjacentSplits = true;
1360 // Among variants of split method select one compliant with adjacent volumes
1362 TSplitMethod method;
1363 if ( !vol.Element()->IsPoly() && !is24TetMode )
1365 int nbVariants = 2, nbTet = 0;
1366 const int** connVariants = 0;
1367 switch ( vol.Element()->GetEntityType() )
1369 case SMDSEntity_Hexa:
1370 case SMDSEntity_Quad_Hexa:
1371 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1372 connVariants = theHexTo5, nbTet = 5;
1374 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1376 case SMDSEntity_Pyramid:
1377 case SMDSEntity_Quad_Pyramid:
1378 connVariants = thePyraTo2; nbTet = 2;
1380 case SMDSEntity_Penta:
1381 case SMDSEntity_Quad_Penta:
1382 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1387 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1389 // check method compliancy with adjacent tetras,
1390 // all found splits must be among facets of tetras described by this method
1391 method = TSplitMethod( nbTet, connVariants[variant] );
1392 if ( hasAdjacentSplits && method._nbTetra > 0 )
1394 bool facetCreated = true;
1395 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1397 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1398 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1399 facetCreated = method.hasFacet( *facet );
1401 if ( !facetCreated )
1402 method = TSplitMethod(0); // incompatible method
1406 if ( method._nbTetra < 1 )
1408 // No standard method is applicable, use a generic solution:
1409 // each facet of a volume is split into triangles and
1410 // each of triangles and a volume barycenter form a tetrahedron.
1412 int* connectivity = new int[ maxTetConnSize + 1 ];
1413 method._connectivity = connectivity;
1414 method._ownConn = true;
1415 method._baryNode = true;
1418 int baryCenInd = vol.NbNodes();
1419 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1421 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1422 const int* nInd = vol.GetFaceNodesIndices( iF );
1423 // find common node of triangle facets of tetra to create
1424 int iCommon = 0; // index in linear numeration
1425 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1426 if ( !triaSplits.empty() )
1429 const TTriangleFacet* facet = &triaSplits.front();
1430 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1431 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1432 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1435 else if ( nbNodes > 3 && !is24TetMode )
1437 // find the best method of splitting into triangles by aspect ratio
1438 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1439 map< double, int > badness2iCommon;
1440 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1441 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1442 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1443 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1445 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1446 nodes[ iQ*((iLast-1)%nbNodes)],
1447 nodes[ iQ*((iLast )%nbNodes)]);
1448 double badness = getBadRate( &tria, aspectRatio );
1449 badness2iCommon.insert( make_pair( badness, iCommon ));
1451 // use iCommon with lowest badness
1452 iCommon = badness2iCommon.begin()->second;
1454 if ( iCommon >= nbNodes )
1455 iCommon = 0; // something wrong
1457 // fill connectivity of tetrahedra based on a current face
1458 int nbTet = nbNodes - 2;
1459 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1461 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1462 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1464 for ( int i = 0; i < nbTet; ++i )
1466 int i1 = i, i2 = (i+1) % nbNodes;
1467 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1468 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1469 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1470 connectivity[ connSize++ ] = faceBaryCenInd;
1471 connectivity[ connSize++ ] = baryCenInd;
1476 for ( int i = 0; i < nbTet; ++i )
1478 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1479 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1480 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1481 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1482 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1483 connectivity[ connSize++ ] = baryCenInd;
1486 method._nbTetra += nbTet;
1488 connectivity[ connSize++ ] = -1;
1492 //================================================================================
1494 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1496 //================================================================================
1498 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1500 // find the tetrahedron including the three nodes of facet
1501 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1502 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1503 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1504 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1505 while ( volIt1->more() )
1507 const SMDS_MeshElement* v = volIt1->next();
1508 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1510 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1511 while ( volIt2->more() )
1512 if ( v != volIt2->next() )
1514 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1515 while ( volIt3->more() )
1516 if ( v == volIt3->next() )
1522 //=======================================================================
1524 * \brief A key of a face of volume
1526 //=======================================================================
1528 struct TVolumeFaceKey: pair< int, pair< int, int> >
1530 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1532 TIDSortedNodeSet sortedNodes;
1533 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1534 int nbNodes = vol.NbFaceNodes( iF );
1535 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1536 for ( int i = 0; i < nbNodes; i += iQ )
1537 sortedNodes.insert( fNodes[i] );
1538 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1539 first = (*(n++))->GetID();
1540 second.first = (*(n++))->GetID();
1541 second.second = (*(n++))->GetID();
1546 //=======================================================================
1547 //function : SplitVolumesIntoTetra
1548 //purpose : Split volumic elements into tetrahedra.
1549 //=======================================================================
1551 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1552 const int theMethodFlags)
1554 // std-like iterator on coordinates of nodes of mesh element
1555 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1556 NXyzIterator xyzEnd;
1558 SMDS_VolumeTool volTool;
1559 SMESH_MesherHelper helper( *GetMesh());
1561 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1562 SMESHDS_SubMesh* fSubMesh = subMesh;
1564 SMESH_SequenceOfElemPtr newNodes, newElems;
1566 // map face of volume to it's baricenrtic node
1567 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1570 TIDSortedElemSet::const_iterator elem = theElems.begin();
1571 for ( ; elem != theElems.end(); ++elem )
1573 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1574 if ( geomType <= SMDSEntity_Quad_Tetra )
1575 continue; // tetra or face or ...
1577 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1579 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1580 if ( splitMethod._nbTetra < 1 ) continue;
1582 // find submesh to add new tetras to
1583 if ( !subMesh || !subMesh->Contains( *elem ))
1585 int shapeID = FindShape( *elem );
1586 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1587 subMesh = GetMeshDS()->MeshElements( shapeID );
1590 if ( (*elem)->IsQuadratic() )
1593 // add quadratic links to the helper
1594 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1596 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1597 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1598 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1600 helper.SetIsQuadratic( true );
1605 helper.SetIsQuadratic( false );
1607 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1608 if ( splitMethod._baryNode )
1610 // make a node at barycenter
1611 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1612 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1613 nodes.push_back( gcNode );
1614 newNodes.Append( gcNode );
1616 if ( !splitMethod._faceBaryNode.empty() )
1618 // make or find baricentric nodes of faces
1619 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1620 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1622 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1623 volFace2BaryNode.insert
1624 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1627 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1628 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1630 nodes.push_back( iF_n->second = f_n->second );
1635 helper.SetElementsOnShape( true );
1636 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1637 const int* tetConn = splitMethod._connectivity;
1638 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1639 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1640 nodes[ tetConn[1] ],
1641 nodes[ tetConn[2] ],
1642 nodes[ tetConn[3] ]));
1644 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1646 // Split faces on sides of the split volume
1648 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1649 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1651 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1652 if ( nbNodes < 4 ) continue;
1654 // find an existing face
1655 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1656 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1657 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1660 helper.SetElementsOnShape( false );
1661 vector< const SMDS_MeshElement* > triangles;
1663 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1664 if ( iF_n != splitMethod._faceBaryNode.end() )
1666 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1668 const SMDS_MeshNode* n1 = fNodes[iN];
1669 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1670 const SMDS_MeshNode *n3 = iF_n->second;
1671 if ( !volTool.IsFaceExternal( iF ))
1673 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1678 // among possible triangles create ones discribed by split method
1679 const int* nInd = volTool.GetFaceNodesIndices( iF );
1680 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1681 int iCom = 0; // common node of triangle faces to split into
1682 list< TTriangleFacet > facets;
1683 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1685 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1686 nInd[ iQ * ( (iCom+1)%nbNodes )],
1687 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1688 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1689 nInd[ iQ * ( (iCom+2)%nbNodes )],
1690 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1691 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1693 facets.push_back( t012 );
1694 facets.push_back( t023 );
1695 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1696 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1697 nInd[ iQ * ((iLast-1)%nbNodes )],
1698 nInd[ iQ * ((iLast )%nbNodes )]));
1702 list< TTriangleFacet >::iterator facet = facets.begin();
1703 for ( ; facet != facets.end(); ++facet )
1705 if ( !volTool.IsFaceExternal( iF ))
1706 swap( facet->_n2, facet->_n3 );
1707 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1708 volNodes[ facet->_n2 ],
1709 volNodes[ facet->_n3 ]));
1712 // find submesh to add new triangles in
1713 if ( !fSubMesh || !fSubMesh->Contains( face ))
1715 int shapeID = FindShape( face );
1716 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1718 for ( int i = 0; i < triangles.size(); ++i )
1720 if ( !triangles.back() ) continue;
1722 fSubMesh->AddElement( triangles.back());
1723 newElems.Append( triangles.back() );
1725 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1726 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1729 } // loop on volume faces to split them into triangles
1731 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1733 } // loop on volumes to split
1735 myLastCreatedNodes = newNodes;
1736 myLastCreatedElems = newElems;
1739 //=======================================================================
1740 //function : AddToSameGroups
1741 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1742 //=======================================================================
1744 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1745 const SMDS_MeshElement* elemInGroups,
1746 SMESHDS_Mesh * aMesh)
1748 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1749 if (!groups.empty()) {
1750 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1751 for ( ; grIt != groups.end(); grIt++ ) {
1752 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1753 if ( group && group->Contains( elemInGroups ))
1754 group->SMDSGroup().Add( elemToAdd );
1760 //=======================================================================
1761 //function : RemoveElemFromGroups
1762 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1763 //=======================================================================
1764 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1765 SMESHDS_Mesh * aMesh)
1767 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1768 if (!groups.empty())
1770 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1771 for (; GrIt != groups.end(); GrIt++)
1773 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1774 if (!grp || grp->IsEmpty()) continue;
1775 grp->SMDSGroup().Remove(removeelem);
1780 //================================================================================
1782 * \brief Replace elemToRm by elemToAdd in the all groups
1784 //================================================================================
1786 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1787 const SMDS_MeshElement* elemToAdd,
1788 SMESHDS_Mesh * aMesh)
1790 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1791 if (!groups.empty()) {
1792 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1793 for ( ; grIt != groups.end(); grIt++ ) {
1794 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1795 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1796 group->SMDSGroup().Add( elemToAdd );
1801 //================================================================================
1803 * \brief Replace elemToRm by elemToAdd in the all groups
1805 //================================================================================
1807 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1808 const vector<const SMDS_MeshElement*>& elemToAdd,
1809 SMESHDS_Mesh * aMesh)
1811 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1812 if (!groups.empty())
1814 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1815 for ( ; grIt != groups.end(); grIt++ ) {
1816 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1817 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1818 for ( int i = 0; i < elemToAdd.size(); ++i )
1819 group->SMDSGroup().Add( elemToAdd[ i ] );
1824 //=======================================================================
1825 //function : QuadToTri
1826 //purpose : Cut quadrangles into triangles.
1827 // theCrit is used to select a diagonal to cut
1828 //=======================================================================
1830 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1831 const bool the13Diag)
1833 myLastCreatedElems.Clear();
1834 myLastCreatedNodes.Clear();
1836 MESSAGE( "::QuadToTri()" );
1838 SMESHDS_Mesh * aMesh = GetMeshDS();
1840 Handle(Geom_Surface) surface;
1841 SMESH_MesherHelper helper( *GetMesh() );
1843 TIDSortedElemSet::iterator itElem;
1844 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1845 const SMDS_MeshElement* elem = *itElem;
1846 if ( !elem || elem->GetType() != SMDSAbs_Face )
1848 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1849 if(!isquad) continue;
1851 if(elem->NbNodes()==4) {
1852 // retrieve element nodes
1853 const SMDS_MeshNode* aNodes [4];
1854 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1856 while ( itN->more() )
1857 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1859 int aShapeId = FindShape( elem );
1860 const SMDS_MeshElement* newElem1 = 0;
1861 const SMDS_MeshElement* newElem2 = 0;
1863 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1864 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1867 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1868 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1870 myLastCreatedElems.Append(newElem1);
1871 myLastCreatedElems.Append(newElem2);
1872 // put a new triangle on the same shape and add to the same groups
1875 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1876 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1878 AddToSameGroups( newElem1, elem, aMesh );
1879 AddToSameGroups( newElem2, elem, aMesh );
1880 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1881 aMesh->RemoveElement( elem );
1884 // Quadratic quadrangle
1886 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1888 // get surface elem is on
1889 int aShapeId = FindShape( elem );
1890 if ( aShapeId != helper.GetSubShapeID() ) {
1894 shape = aMesh->IndexToShape( aShapeId );
1895 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1896 TopoDS_Face face = TopoDS::Face( shape );
1897 surface = BRep_Tool::Surface( face );
1898 if ( !surface.IsNull() )
1899 helper.SetSubShape( shape );
1903 const SMDS_MeshNode* aNodes [8];
1904 const SMDS_MeshNode* inFaceNode = 0;
1905 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1907 while ( itN->more() ) {
1908 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1909 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1910 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1912 inFaceNode = aNodes[ i-1 ];
1916 // find middle point for (0,1,2,3)
1917 // and create a node in this point;
1919 if ( surface.IsNull() ) {
1921 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1925 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1928 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1930 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1932 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1933 myLastCreatedNodes.Append(newN);
1935 // create a new element
1936 const SMDS_MeshElement* newElem1 = 0;
1937 const SMDS_MeshElement* newElem2 = 0;
1938 const SMDS_MeshNode* N[6];
1946 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1947 aNodes[6], aNodes[7], newN );
1948 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1949 newN, aNodes[4], aNodes[5] );
1958 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1959 aNodes[7], aNodes[4], newN );
1960 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1961 newN, aNodes[5], aNodes[6] );
1963 myLastCreatedElems.Append(newElem1);
1964 myLastCreatedElems.Append(newElem2);
1965 // put a new triangle on the same shape and add to the same groups
1968 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1969 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1971 AddToSameGroups( newElem1, elem, aMesh );
1972 AddToSameGroups( newElem2, elem, aMesh );
1973 aMesh->RemoveElement( elem );
1980 //=======================================================================
1981 //function : getAngle
1983 //=======================================================================
1985 double getAngle(const SMDS_MeshElement * tr1,
1986 const SMDS_MeshElement * tr2,
1987 const SMDS_MeshNode * n1,
1988 const SMDS_MeshNode * n2)
1990 double angle = 2*PI; // bad angle
1993 SMESH::Controls::TSequenceOfXYZ P1, P2;
1994 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1995 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1998 if(!tr1->IsQuadratic())
1999 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2001 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2002 if ( N1.SquareMagnitude() <= gp::Resolution() )
2004 if(!tr2->IsQuadratic())
2005 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2007 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2008 if ( N2.SquareMagnitude() <= gp::Resolution() )
2011 // find the first diagonal node n1 in the triangles:
2012 // take in account a diagonal link orientation
2013 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2014 for ( int t = 0; t < 2; t++ ) {
2015 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2016 int i = 0, iDiag = -1;
2017 while ( it->more()) {
2018 const SMDS_MeshElement *n = it->next();
2019 if ( n == n1 || n == n2 ) {
2023 if ( i - iDiag == 1 )
2024 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2033 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2036 angle = N1.Angle( N2 );
2041 // =================================================
2042 // class generating a unique ID for a pair of nodes
2043 // and able to return nodes by that ID
2044 // =================================================
2048 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2049 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2052 long GetLinkID (const SMDS_MeshNode * n1,
2053 const SMDS_MeshNode * n2) const
2055 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2058 bool GetNodes (const long theLinkID,
2059 const SMDS_MeshNode* & theNode1,
2060 const SMDS_MeshNode* & theNode2) const
2062 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2063 if ( !theNode1 ) return false;
2064 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2065 if ( !theNode2 ) return false;
2071 const SMESHDS_Mesh* myMesh;
2076 //=======================================================================
2077 //function : TriToQuad
2078 //purpose : Fuse neighbour triangles into quadrangles.
2079 // theCrit is used to select a neighbour to fuse with.
2080 // theMaxAngle is a max angle between element normals at which
2081 // fusion is still performed.
2082 //=======================================================================
2084 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2085 SMESH::Controls::NumericalFunctorPtr theCrit,
2086 const double theMaxAngle)
2088 myLastCreatedElems.Clear();
2089 myLastCreatedNodes.Clear();
2091 MESSAGE( "::TriToQuad()" );
2093 if ( !theCrit.get() )
2096 SMESHDS_Mesh * aMesh = GetMeshDS();
2098 // Prepare data for algo: build
2099 // 1. map of elements with their linkIDs
2100 // 2. map of linkIDs with their elements
2102 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2103 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2104 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2105 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2107 TIDSortedElemSet::iterator itElem;
2108 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2109 const SMDS_MeshElement* elem = *itElem;
2110 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2111 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2112 if(!IsTria) continue;
2114 // retrieve element nodes
2115 const SMDS_MeshNode* aNodes [4];
2116 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2119 aNodes[ i++ ] = cast2Node( itN->next() );
2120 aNodes[ 3 ] = aNodes[ 0 ];
2123 for ( i = 0; i < 3; i++ ) {
2124 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2125 // check if elements sharing a link can be fused
2126 itLE = mapLi_listEl.find( link );
2127 if ( itLE != mapLi_listEl.end() ) {
2128 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2130 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2131 //if ( FindShape( elem ) != FindShape( elem2 ))
2132 // continue; // do not fuse triangles laying on different shapes
2133 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2134 continue; // avoid making badly shaped quads
2135 (*itLE).second.push_back( elem );
2138 mapLi_listEl[ link ].push_back( elem );
2140 mapEl_setLi [ elem ].insert( link );
2143 // Clean the maps from the links shared by a sole element, ie
2144 // links to which only one element is bound in mapLi_listEl
2146 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2147 int nbElems = (*itLE).second.size();
2148 if ( nbElems < 2 ) {
2149 const SMDS_MeshElement* elem = (*itLE).second.front();
2150 SMESH_TLink link = (*itLE).first;
2151 mapEl_setLi[ elem ].erase( link );
2152 if ( mapEl_setLi[ elem ].empty() )
2153 mapEl_setLi.erase( elem );
2157 // Algo: fuse triangles into quadrangles
2159 while ( ! mapEl_setLi.empty() ) {
2160 // Look for the start element:
2161 // the element having the least nb of shared links
2162 const SMDS_MeshElement* startElem = 0;
2164 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2165 int nbLinks = (*itEL).second.size();
2166 if ( nbLinks < minNbLinks ) {
2167 startElem = (*itEL).first;
2168 minNbLinks = nbLinks;
2169 if ( minNbLinks == 1 )
2174 // search elements to fuse starting from startElem or links of elements
2175 // fused earlyer - startLinks
2176 list< SMESH_TLink > startLinks;
2177 while ( startElem || !startLinks.empty() ) {
2178 while ( !startElem && !startLinks.empty() ) {
2179 // Get an element to start, by a link
2180 SMESH_TLink linkId = startLinks.front();
2181 startLinks.pop_front();
2182 itLE = mapLi_listEl.find( linkId );
2183 if ( itLE != mapLi_listEl.end() ) {
2184 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2185 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2186 for ( ; itE != listElem.end() ; itE++ )
2187 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2189 mapLi_listEl.erase( itLE );
2194 // Get candidates to be fused
2195 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2196 const SMESH_TLink *link12, *link13;
2198 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2199 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2200 ASSERT( !setLi.empty() );
2201 set< SMESH_TLink >::iterator itLi;
2202 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2204 const SMESH_TLink & link = (*itLi);
2205 itLE = mapLi_listEl.find( link );
2206 if ( itLE == mapLi_listEl.end() )
2209 const SMDS_MeshElement* elem = (*itLE).second.front();
2211 elem = (*itLE).second.back();
2212 mapLi_listEl.erase( itLE );
2213 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2224 // add other links of elem to list of links to re-start from
2225 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2226 set< SMESH_TLink >::iterator it;
2227 for ( it = links.begin(); it != links.end(); it++ ) {
2228 const SMESH_TLink& link2 = (*it);
2229 if ( link2 != link )
2230 startLinks.push_back( link2 );
2234 // Get nodes of possible quadrangles
2235 const SMDS_MeshNode *n12 [4], *n13 [4];
2236 bool Ok12 = false, Ok13 = false;
2237 const SMDS_MeshNode *linkNode1, *linkNode2;
2239 linkNode1 = link12->first;
2240 linkNode2 = link12->second;
2241 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2245 linkNode1 = link13->first;
2246 linkNode2 = link13->second;
2247 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2251 // Choose a pair to fuse
2252 if ( Ok12 && Ok13 ) {
2253 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2254 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2255 double aBadRate12 = getBadRate( &quad12, theCrit );
2256 double aBadRate13 = getBadRate( &quad13, theCrit );
2257 if ( aBadRate13 < aBadRate12 )
2264 // and remove fused elems and removed links from the maps
2265 mapEl_setLi.erase( tr1 );
2267 mapEl_setLi.erase( tr2 );
2268 mapLi_listEl.erase( *link12 );
2269 if(tr1->NbNodes()==3) {
2270 const SMDS_MeshElement* newElem = 0;
2271 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2272 myLastCreatedElems.Append(newElem);
2273 AddToSameGroups( newElem, tr1, aMesh );
2274 int aShapeId = tr1->getshapeId();
2277 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2279 aMesh->RemoveElement( tr1 );
2280 aMesh->RemoveElement( tr2 );
2283 const SMDS_MeshNode* N1 [6];
2284 const SMDS_MeshNode* N2 [6];
2285 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2286 // now we receive following N1 and N2 (using numeration as above image)
2287 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2288 // i.e. first nodes from both arrays determ new diagonal
2289 const SMDS_MeshNode* aNodes[8];
2298 const SMDS_MeshElement* newElem = 0;
2299 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2300 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2301 myLastCreatedElems.Append(newElem);
2302 AddToSameGroups( newElem, tr1, aMesh );
2303 int aShapeId = tr1->getshapeId();
2306 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2308 aMesh->RemoveElement( tr1 );
2309 aMesh->RemoveElement( tr2 );
2310 // remove middle node (9)
2311 GetMeshDS()->RemoveNode( N1[4] );
2315 mapEl_setLi.erase( tr3 );
2316 mapLi_listEl.erase( *link13 );
2317 if(tr1->NbNodes()==3) {
2318 const SMDS_MeshElement* newElem = 0;
2319 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2320 myLastCreatedElems.Append(newElem);
2321 AddToSameGroups( newElem, tr1, aMesh );
2322 int aShapeId = tr1->getshapeId();
2325 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2327 aMesh->RemoveElement( tr1 );
2328 aMesh->RemoveElement( tr3 );
2331 const SMDS_MeshNode* N1 [6];
2332 const SMDS_MeshNode* N2 [6];
2333 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2334 // now we receive following N1 and N2 (using numeration as above image)
2335 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2336 // i.e. first nodes from both arrays determ new diagonal
2337 const SMDS_MeshNode* aNodes[8];
2346 const SMDS_MeshElement* newElem = 0;
2347 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2348 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2349 myLastCreatedElems.Append(newElem);
2350 AddToSameGroups( newElem, tr1, aMesh );
2351 int aShapeId = tr1->getshapeId();
2354 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2356 aMesh->RemoveElement( tr1 );
2357 aMesh->RemoveElement( tr3 );
2358 // remove middle node (9)
2359 GetMeshDS()->RemoveNode( N1[4] );
2363 // Next element to fuse: the rejected one
2365 startElem = Ok12 ? tr3 : tr2;
2367 } // if ( startElem )
2368 } // while ( startElem || !startLinks.empty() )
2369 } // while ( ! mapEl_setLi.empty() )
2375 /*#define DUMPSO(txt) \
2376 // cout << txt << endl;
2377 //=============================================================================
2381 //=============================================================================
2382 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2386 int tmp = idNodes[ i1 ];
2387 idNodes[ i1 ] = idNodes[ i2 ];
2388 idNodes[ i2 ] = tmp;
2389 gp_Pnt Ptmp = P[ i1 ];
2392 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2395 //=======================================================================
2396 //function : SortQuadNodes
2397 //purpose : Set 4 nodes of a quadrangle face in a good order.
2398 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2400 //=======================================================================
2402 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2407 for ( i = 0; i < 4; i++ ) {
2408 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2410 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2413 gp_Vec V1(P[0], P[1]);
2414 gp_Vec V2(P[0], P[2]);
2415 gp_Vec V3(P[0], P[3]);
2417 gp_Vec Cross1 = V1 ^ V2;
2418 gp_Vec Cross2 = V2 ^ V3;
2421 if (Cross1.Dot(Cross2) < 0)
2426 if (Cross1.Dot(Cross2) < 0)
2430 swap ( i, i + 1, idNodes, P );
2432 // for ( int ii = 0; ii < 4; ii++ ) {
2433 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2434 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2440 //=======================================================================
2441 //function : SortHexaNodes
2442 //purpose : Set 8 nodes of a hexahedron in a good order.
2443 // Return success status
2444 //=======================================================================
2446 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2451 DUMPSO( "INPUT: ========================================");
2452 for ( i = 0; i < 8; i++ ) {
2453 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2454 if ( !n ) return false;
2455 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2456 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2458 DUMPSO( "========================================");
2461 set<int> faceNodes; // ids of bottom face nodes, to be found
2462 set<int> checkedId1; // ids of tried 2-nd nodes
2463 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2464 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2465 int iMin, iLoop1 = 0;
2467 // Loop to try the 2-nd nodes
2469 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2471 // Find not checked 2-nd node
2472 for ( i = 1; i < 8; i++ )
2473 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2474 int id1 = idNodes[i];
2475 swap ( 1, i, idNodes, P );
2476 checkedId1.insert ( id1 );
2480 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2481 // ie that all but meybe one (id3 which is on the same face) nodes
2482 // lay on the same side from the triangle plane.
2484 bool manyInPlane = false; // more than 4 nodes lay in plane
2486 while ( ++iLoop2 < 6 ) {
2488 // get 1-2-3 plane coeffs
2489 Standard_Real A, B, C, D;
2490 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2491 if ( N.SquareMagnitude() > gp::Resolution() )
2493 gp_Pln pln ( P[0], N );
2494 pln.Coefficients( A, B, C, D );
2496 // find the node (iMin) closest to pln
2497 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2499 for ( i = 3; i < 8; i++ ) {
2500 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2501 if ( fabs( dist[i] ) < minDist ) {
2502 minDist = fabs( dist[i] );
2505 if ( fabs( dist[i] ) <= tol )
2506 idInPln.insert( idNodes[i] );
2509 // there should not be more than 4 nodes in bottom plane
2510 if ( idInPln.size() > 1 )
2512 DUMPSO( "### idInPln.size() = " << idInPln.size());
2513 // idInPlane does not contain the first 3 nodes
2514 if ( manyInPlane || idInPln.size() == 5)
2515 return false; // all nodes in one plane
2518 // set the 1-st node to be not in plane
2519 for ( i = 3; i < 8; i++ ) {
2520 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2521 DUMPSO( "### Reset 0-th node");
2522 swap( 0, i, idNodes, P );
2527 // reset to re-check second nodes
2528 leastDist = DBL_MAX;
2532 break; // from iLoop2;
2535 // check that the other 4 nodes are on the same side
2536 bool sameSide = true;
2537 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2538 for ( i = 3; sameSide && i < 8; i++ ) {
2540 sameSide = ( isNeg == dist[i] <= 0.);
2543 // keep best solution
2544 if ( sameSide && minDist < leastDist ) {
2545 leastDist = minDist;
2547 faceNodes.insert( idNodes[ 1 ] );
2548 faceNodes.insert( idNodes[ 2 ] );
2549 faceNodes.insert( idNodes[ iMin ] );
2550 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2551 << " leastDist = " << leastDist);
2552 if ( leastDist <= DBL_MIN )
2557 // set next 3-d node to check
2558 int iNext = 2 + iLoop2;
2560 DUMPSO( "Try 2-nd");
2561 swap ( 2, iNext, idNodes, P );
2563 } // while ( iLoop2 < 6 )
2566 if ( faceNodes.empty() ) return false;
2568 // Put the faceNodes in proper places
2569 for ( i = 4; i < 8; i++ ) {
2570 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2571 // find a place to put
2573 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2575 DUMPSO( "Set faceNodes");
2576 swap ( iTo, i, idNodes, P );
2581 // Set nodes of the found bottom face in good order
2582 DUMPSO( " Found bottom face: ");
2583 i = SortQuadNodes( theMesh, idNodes );
2585 gp_Pnt Ptmp = P[ i ];
2590 // for ( int ii = 0; ii < 4; ii++ ) {
2591 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2592 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2595 // Gravity center of the top and bottom faces
2596 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2597 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2599 // Get direction from the bottom to the top face
2600 gp_Vec upDir ( aGCb, aGCt );
2601 Standard_Real upDirSize = upDir.Magnitude();
2602 if ( upDirSize <= gp::Resolution() ) return false;
2605 // Assure that the bottom face normal points up
2606 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2607 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2608 if ( Nb.Dot( upDir ) < 0 ) {
2609 DUMPSO( "Reverse bottom face");
2610 swap( 1, 3, idNodes, P );
2613 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2614 Standard_Real minDist = DBL_MAX;
2615 for ( i = 4; i < 8; i++ ) {
2616 // projection of P[i] to the plane defined by P[0] and upDir
2617 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2618 Standard_Real sqDist = P[0].SquareDistance( Pp );
2619 if ( sqDist < minDist ) {
2624 DUMPSO( "Set 4-th");
2625 swap ( 4, iMin, idNodes, P );
2627 // Set nodes of the top face in good order
2628 DUMPSO( "Sort top face");
2629 i = SortQuadNodes( theMesh, &idNodes[4] );
2632 gp_Pnt Ptmp = P[ i ];
2637 // Assure that direction of the top face normal is from the bottom face
2638 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2639 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2640 if ( Nt.Dot( upDir ) < 0 ) {
2641 DUMPSO( "Reverse top face");
2642 swap( 5, 7, idNodes, P );
2645 // DUMPSO( "OUTPUT: ========================================");
2646 // for ( i = 0; i < 8; i++ ) {
2647 // float *p = ugrid->GetPoint(idNodes[i]);
2648 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2654 //================================================================================
2656 * \brief Return nodes linked to the given one
2657 * \param theNode - the node
2658 * \param linkedNodes - the found nodes
2659 * \param type - the type of elements to check
2661 * Medium nodes are ignored
2663 //================================================================================
2665 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2666 TIDSortedElemSet & linkedNodes,
2667 SMDSAbs_ElementType type )
2669 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2670 while ( elemIt->more() )
2672 const SMDS_MeshElement* elem = elemIt->next();
2673 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2674 if ( elem->GetType() == SMDSAbs_Volume )
2676 SMDS_VolumeTool vol( elem );
2677 while ( nodeIt->more() ) {
2678 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2679 if ( theNode != n && vol.IsLinked( theNode, n ))
2680 linkedNodes.insert( n );
2685 for ( int i = 0; nodeIt->more(); ++i ) {
2686 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2687 if ( n == theNode ) {
2688 int iBefore = i - 1;
2690 if ( elem->IsQuadratic() ) {
2691 int nb = elem->NbNodes() / 2;
2692 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2693 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2695 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2696 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2703 //=======================================================================
2704 //function : laplacianSmooth
2705 //purpose : pulls theNode toward the center of surrounding nodes directly
2706 // connected to that node along an element edge
2707 //=======================================================================
2709 void laplacianSmooth(const SMDS_MeshNode* theNode,
2710 const Handle(Geom_Surface)& theSurface,
2711 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2713 // find surrounding nodes
2715 TIDSortedElemSet nodeSet;
2716 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2718 // compute new coodrs
2720 double coord[] = { 0., 0., 0. };
2721 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2722 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2723 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2724 if ( theSurface.IsNull() ) { // smooth in 3D
2725 coord[0] += node->X();
2726 coord[1] += node->Y();
2727 coord[2] += node->Z();
2729 else { // smooth in 2D
2730 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2731 gp_XY* uv = theUVMap[ node ];
2732 coord[0] += uv->X();
2733 coord[1] += uv->Y();
2736 int nbNodes = nodeSet.size();
2739 coord[0] /= nbNodes;
2740 coord[1] /= nbNodes;
2742 if ( !theSurface.IsNull() ) {
2743 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2744 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2745 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2751 coord[2] /= nbNodes;
2755 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2758 //=======================================================================
2759 //function : centroidalSmooth
2760 //purpose : pulls theNode toward the element-area-weighted centroid of the
2761 // surrounding elements
2762 //=======================================================================
2764 void centroidalSmooth(const SMDS_MeshNode* theNode,
2765 const Handle(Geom_Surface)& theSurface,
2766 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2768 gp_XYZ aNewXYZ(0.,0.,0.);
2769 SMESH::Controls::Area anAreaFunc;
2770 double totalArea = 0.;
2775 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2776 while ( elemIt->more() )
2778 const SMDS_MeshElement* elem = elemIt->next();
2781 gp_XYZ elemCenter(0.,0.,0.);
2782 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2783 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2784 int nn = elem->NbNodes();
2785 if(elem->IsQuadratic()) nn = nn/2;
2787 //while ( itN->more() ) {
2789 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2791 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2792 aNodePoints.push_back( aP );
2793 if ( !theSurface.IsNull() ) { // smooth in 2D
2794 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2795 gp_XY* uv = theUVMap[ aNode ];
2796 aP.SetCoord( uv->X(), uv->Y(), 0. );
2800 double elemArea = anAreaFunc.GetValue( aNodePoints );
2801 totalArea += elemArea;
2803 aNewXYZ += elemCenter * elemArea;
2805 aNewXYZ /= totalArea;
2806 if ( !theSurface.IsNull() ) {
2807 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2808 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2813 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2816 //=======================================================================
2817 //function : getClosestUV
2818 //purpose : return UV of closest projection
2819 //=======================================================================
2821 static bool getClosestUV (Extrema_GenExtPS& projector,
2822 const gp_Pnt& point,
2825 projector.Perform( point );
2826 if ( projector.IsDone() ) {
2827 double u, v, minVal = DBL_MAX;
2828 for ( int i = projector.NbExt(); i > 0; i-- )
2829 if ( projector.Value( i ) < minVal ) {
2830 minVal = projector.Value( i );
2831 projector.Point( i ).Parameter( u, v );
2833 result.SetCoord( u, v );
2839 //=======================================================================
2841 //purpose : Smooth theElements during theNbIterations or until a worst
2842 // element has aspect ratio <= theTgtAspectRatio.
2843 // Aspect Ratio varies in range [1.0, inf].
2844 // If theElements is empty, the whole mesh is smoothed.
2845 // theFixedNodes contains additionally fixed nodes. Nodes built
2846 // on edges and boundary nodes are always fixed.
2847 //=======================================================================
2849 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2850 set<const SMDS_MeshNode*> & theFixedNodes,
2851 const SmoothMethod theSmoothMethod,
2852 const int theNbIterations,
2853 double theTgtAspectRatio,
2856 myLastCreatedElems.Clear();
2857 myLastCreatedNodes.Clear();
2859 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2861 if ( theTgtAspectRatio < 1.0 )
2862 theTgtAspectRatio = 1.0;
2864 const double disttol = 1.e-16;
2866 SMESH::Controls::AspectRatio aQualityFunc;
2868 SMESHDS_Mesh* aMesh = GetMeshDS();
2870 if ( theElems.empty() ) {
2871 // add all faces to theElems
2872 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2873 while ( fIt->more() ) {
2874 const SMDS_MeshElement* face = fIt->next();
2875 theElems.insert( face );
2878 // get all face ids theElems are on
2879 set< int > faceIdSet;
2880 TIDSortedElemSet::iterator itElem;
2882 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2883 int fId = FindShape( *itElem );
2884 // check that corresponding submesh exists and a shape is face
2886 faceIdSet.find( fId ) == faceIdSet.end() &&
2887 aMesh->MeshElements( fId )) {
2888 TopoDS_Shape F = aMesh->IndexToShape( fId );
2889 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2890 faceIdSet.insert( fId );
2893 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2895 // ===============================================
2896 // smooth elements on each TopoDS_Face separately
2897 // ===============================================
2899 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2900 for ( ; fId != faceIdSet.rend(); ++fId ) {
2901 // get face surface and submesh
2902 Handle(Geom_Surface) surface;
2903 SMESHDS_SubMesh* faceSubMesh = 0;
2905 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2906 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2907 bool isUPeriodic = false, isVPeriodic = false;
2909 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2910 surface = BRep_Tool::Surface( face );
2911 faceSubMesh = aMesh->MeshElements( *fId );
2912 fToler2 = BRep_Tool::Tolerance( face );
2913 fToler2 *= fToler2 * 10.;
2914 isUPeriodic = surface->IsUPeriodic();
2916 vPeriod = surface->UPeriod();
2917 isVPeriodic = surface->IsVPeriodic();
2919 uPeriod = surface->VPeriod();
2920 surface->Bounds( u1, u2, v1, v2 );
2922 // ---------------------------------------------------------
2923 // for elements on a face, find movable and fixed nodes and
2924 // compute UV for them
2925 // ---------------------------------------------------------
2926 bool checkBoundaryNodes = false;
2927 bool isQuadratic = false;
2928 set<const SMDS_MeshNode*> setMovableNodes;
2929 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2930 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2931 list< const SMDS_MeshElement* > elemsOnFace;
2933 Extrema_GenExtPS projector;
2934 GeomAdaptor_Surface surfAdaptor;
2935 if ( !surface.IsNull() ) {
2936 surfAdaptor.Load( surface );
2937 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2939 int nbElemOnFace = 0;
2940 itElem = theElems.begin();
2941 // loop on not yet smoothed elements: look for elems on a face
2942 while ( itElem != theElems.end() ) {
2943 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2944 break; // all elements found
2946 const SMDS_MeshElement* elem = *itElem;
2947 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2948 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2952 elemsOnFace.push_back( elem );
2953 theElems.erase( itElem++ );
2957 isQuadratic = elem->IsQuadratic();
2959 // get movable nodes of elem
2960 const SMDS_MeshNode* node;
2961 SMDS_TypeOfPosition posType;
2962 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2963 int nn = 0, nbn = elem->NbNodes();
2964 if(elem->IsQuadratic())
2966 while ( nn++ < nbn ) {
2967 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2968 const SMDS_PositionPtr& pos = node->GetPosition();
2969 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2970 if (posType != SMDS_TOP_EDGE &&
2971 posType != SMDS_TOP_VERTEX &&
2972 theFixedNodes.find( node ) == theFixedNodes.end())
2974 // check if all faces around the node are on faceSubMesh
2975 // because a node on edge may be bound to face
2976 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2978 if ( faceSubMesh ) {
2979 while ( eIt->more() && all ) {
2980 const SMDS_MeshElement* e = eIt->next();
2981 all = faceSubMesh->Contains( e );
2985 setMovableNodes.insert( node );
2987 checkBoundaryNodes = true;
2989 if ( posType == SMDS_TOP_3DSPACE )
2990 checkBoundaryNodes = true;
2993 if ( surface.IsNull() )
2996 // get nodes to check UV
2997 list< const SMDS_MeshNode* > uvCheckNodes;
2998 itN = elem->nodesIterator();
2999 nn = 0; nbn = elem->NbNodes();
3000 if(elem->IsQuadratic())
3002 while ( nn++ < nbn ) {
3003 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3004 if ( uvMap.find( node ) == uvMap.end() )
3005 uvCheckNodes.push_back( node );
3006 // add nodes of elems sharing node
3007 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3008 // while ( eIt->more() ) {
3009 // const SMDS_MeshElement* e = eIt->next();
3010 // if ( e != elem ) {
3011 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3012 // while ( nIt->more() ) {
3013 // const SMDS_MeshNode* n =
3014 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3015 // if ( uvMap.find( n ) == uvMap.end() )
3016 // uvCheckNodes.push_back( n );
3022 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3023 for ( ; n != uvCheckNodes.end(); ++n ) {
3026 const SMDS_PositionPtr& pos = node->GetPosition();
3027 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3029 switch ( posType ) {
3030 case SMDS_TOP_FACE: {
3031 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3032 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3035 case SMDS_TOP_EDGE: {
3036 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3037 Handle(Geom2d_Curve) pcurve;
3038 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3039 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3040 if ( !pcurve.IsNull() ) {
3041 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3042 uv = pcurve->Value( u ).XY();
3046 case SMDS_TOP_VERTEX: {
3047 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3048 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3049 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3054 // check existing UV
3055 bool project = true;
3056 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3057 double dist1 = DBL_MAX, dist2 = 0;
3058 if ( posType != SMDS_TOP_3DSPACE ) {
3059 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3060 project = dist1 > fToler2;
3062 if ( project ) { // compute new UV
3064 if ( !getClosestUV( projector, pNode, newUV )) {
3065 MESSAGE("Node Projection Failed " << node);
3069 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3071 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3073 if ( posType != SMDS_TOP_3DSPACE )
3074 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3075 if ( dist2 < dist1 )
3079 // store UV in the map
3080 listUV.push_back( uv );
3081 uvMap.insert( make_pair( node, &listUV.back() ));
3083 } // loop on not yet smoothed elements
3085 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3086 checkBoundaryNodes = true;
3088 // fix nodes on mesh boundary
3090 if ( checkBoundaryNodes ) {
3091 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3092 map< NLink, int >::iterator link_nb;
3093 // put all elements links to linkNbMap
3094 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3095 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3096 const SMDS_MeshElement* elem = (*elemIt);
3097 int nbn = elem->NbNodes();
3098 if(elem->IsQuadratic())
3100 // loop on elem links: insert them in linkNbMap
3101 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3102 for ( int iN = 0; iN < nbn; ++iN ) {
3103 curNode = elem->GetNode( iN );
3105 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3106 else link = make_pair( prevNode , curNode );
3108 link_nb = linkNbMap.find( link );
3109 if ( link_nb == linkNbMap.end() )
3110 linkNbMap.insert( make_pair ( link, 1 ));
3115 // remove nodes that are in links encountered only once from setMovableNodes
3116 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3117 if ( link_nb->second == 1 ) {
3118 setMovableNodes.erase( link_nb->first.first );
3119 setMovableNodes.erase( link_nb->first.second );
3124 // -----------------------------------------------------
3125 // for nodes on seam edge, compute one more UV ( uvMap2 );
3126 // find movable nodes linked to nodes on seam and which
3127 // are to be smoothed using the second UV ( uvMap2 )
3128 // -----------------------------------------------------
3130 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3131 if ( !surface.IsNull() ) {
3132 TopExp_Explorer eExp( face, TopAbs_EDGE );
3133 for ( ; eExp.More(); eExp.Next() ) {
3134 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3135 if ( !BRep_Tool::IsClosed( edge, face ))
3137 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3138 if ( !sm ) continue;
3139 // find out which parameter varies for a node on seam
3142 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3143 if ( pcurve.IsNull() ) continue;
3144 uv1 = pcurve->Value( f );
3146 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3147 if ( pcurve.IsNull() ) continue;
3148 uv2 = pcurve->Value( f );
3149 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3151 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3152 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3154 // get nodes on seam and its vertices
3155 list< const SMDS_MeshNode* > seamNodes;
3156 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3157 while ( nSeamIt->more() ) {
3158 const SMDS_MeshNode* node = nSeamIt->next();
3159 if ( !isQuadratic || !IsMedium( node ))
3160 seamNodes.push_back( node );
3162 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3163 for ( ; vExp.More(); vExp.Next() ) {
3164 sm = aMesh->MeshElements( vExp.Current() );
3166 nSeamIt = sm->GetNodes();
3167 while ( nSeamIt->more() )
3168 seamNodes.push_back( nSeamIt->next() );
3171 // loop on nodes on seam
3172 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3173 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3174 const SMDS_MeshNode* nSeam = *noSeIt;
3175 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3176 if ( n_uv == uvMap.end() )
3179 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3180 // set the second UV
3181 listUV.push_back( *n_uv->second );
3182 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3183 if ( uvMap2.empty() )
3184 uvMap2 = uvMap; // copy the uvMap contents
3185 uvMap2[ nSeam ] = &listUV.back();
3187 // collect movable nodes linked to ones on seam in nodesNearSeam
3188 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3189 while ( eIt->more() ) {
3190 const SMDS_MeshElement* e = eIt->next();
3191 int nbUseMap1 = 0, nbUseMap2 = 0;
3192 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3193 int nn = 0, nbn = e->NbNodes();
3194 if(e->IsQuadratic()) nbn = nbn/2;
3195 while ( nn++ < nbn )
3197 const SMDS_MeshNode* n =
3198 static_cast<const SMDS_MeshNode*>( nIt->next() );
3200 setMovableNodes.find( n ) == setMovableNodes.end() )
3202 // add only nodes being closer to uv2 than to uv1
3203 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3204 0.5 * ( n->Y() + nSeam->Y() ),
3205 0.5 * ( n->Z() + nSeam->Z() ));
3207 getClosestUV( projector, pMid, uv );
3208 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3209 nodesNearSeam.insert( n );
3215 // for centroidalSmooth all element nodes must
3216 // be on one side of a seam
3217 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3218 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3220 while ( nn++ < nbn ) {
3221 const SMDS_MeshNode* n =
3222 static_cast<const SMDS_MeshNode*>( nIt->next() );
3223 setMovableNodes.erase( n );
3227 } // loop on nodes on seam
3228 } // loop on edge of a face
3229 } // if ( !face.IsNull() )
3231 if ( setMovableNodes.empty() ) {
3232 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3233 continue; // goto next face
3241 double maxRatio = -1., maxDisplacement = -1.;
3242 set<const SMDS_MeshNode*>::iterator nodeToMove;
3243 for ( it = 0; it < theNbIterations; it++ ) {
3244 maxDisplacement = 0.;
3245 nodeToMove = setMovableNodes.begin();
3246 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3247 const SMDS_MeshNode* node = (*nodeToMove);
3248 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3251 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3252 if ( theSmoothMethod == LAPLACIAN )
3253 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3255 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3257 // node displacement
3258 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3259 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3260 if ( aDispl > maxDisplacement )
3261 maxDisplacement = aDispl;
3263 // no node movement => exit
3264 //if ( maxDisplacement < 1.e-16 ) {
3265 if ( maxDisplacement < disttol ) {
3266 MESSAGE("-- no node movement --");
3270 // check elements quality
3272 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3273 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3274 const SMDS_MeshElement* elem = (*elemIt);
3275 if ( !elem || elem->GetType() != SMDSAbs_Face )
3277 SMESH::Controls::TSequenceOfXYZ aPoints;
3278 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3279 double aValue = aQualityFunc.GetValue( aPoints );
3280 if ( aValue > maxRatio )
3284 if ( maxRatio <= theTgtAspectRatio ) {
3285 MESSAGE("-- quality achived --");
3288 if (it+1 == theNbIterations) {
3289 MESSAGE("-- Iteration limit exceeded --");
3291 } // smoothing iterations
3293 MESSAGE(" Face id: " << *fId <<
3294 " Nb iterstions: " << it <<
3295 " Displacement: " << maxDisplacement <<
3296 " Aspect Ratio " << maxRatio);
3298 // ---------------------------------------
3299 // new nodes positions are computed,
3300 // record movement in DS and set new UV
3301 // ---------------------------------------
3302 nodeToMove = setMovableNodes.begin();
3303 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3304 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3305 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3306 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3307 if ( node_uv != uvMap.end() ) {
3308 gp_XY* uv = node_uv->second;
3310 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3314 // move medium nodes of quadratic elements
3317 SMESH_MesherHelper helper( *GetMesh() );
3318 if ( !face.IsNull() )
3319 helper.SetSubShape( face );
3320 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3321 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3322 const SMDS_VtkFace* QF =
3323 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3324 if(QF && QF->IsQuadratic()) {
3325 vector<const SMDS_MeshNode*> Ns;
3326 Ns.reserve(QF->NbNodes()+1);
3327 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3328 while ( anIter->more() )
3329 Ns.push_back( cast2Node(anIter->next()) );
3330 Ns.push_back( Ns[0] );
3332 for(int i=0; i<QF->NbNodes(); i=i+2) {
3333 if ( !surface.IsNull() ) {
3334 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3335 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3336 gp_XY uv = ( uv1 + uv2 ) / 2.;
3337 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3338 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3341 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3342 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3343 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3345 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3346 fabs( Ns[i+1]->Y() - y ) > disttol ||
3347 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3348 // we have to move i+1 node
3349 aMesh->MoveNode( Ns[i+1], x, y, z );
3356 } // loop on face ids
3360 //=======================================================================
3361 //function : isReverse
3362 //purpose : Return true if normal of prevNodes is not co-directied with
3363 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3364 // iNotSame is where prevNodes and nextNodes are different
3365 //=======================================================================
3367 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3368 vector<const SMDS_MeshNode*> nextNodes,
3372 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3373 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3375 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3376 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3377 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3378 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3380 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3381 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3382 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3383 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3385 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3387 return (vA ^ vB) * vN < 0.0;
3390 //=======================================================================
3392 * \brief Create elements by sweeping an element
3393 * \param elem - element to sweep
3394 * \param newNodesItVec - nodes generated from each node of the element
3395 * \param newElems - generated elements
3396 * \param nbSteps - number of sweeping steps
3397 * \param srcElements - to append elem for each generated element
3399 //=======================================================================
3401 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3402 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3403 list<const SMDS_MeshElement*>& newElems,
3405 SMESH_SequenceOfElemPtr& srcElements)
3407 //MESSAGE("sweepElement " << nbSteps);
3408 SMESHDS_Mesh* aMesh = GetMeshDS();
3410 // Loop on elem nodes:
3411 // find new nodes and detect same nodes indices
3412 int nbNodes = elem->NbNodes();
3413 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3414 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3415 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3416 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3418 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3419 vector<int> sames(nbNodes);
3420 vector<bool> issimple(nbNodes);
3422 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3423 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3424 const SMDS_MeshNode* node = nnIt->first;
3425 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3426 if ( listNewNodes.empty() ) {
3430 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3432 itNN[ iNode ] = listNewNodes.begin();
3433 prevNod[ iNode ] = node;
3434 nextNod[ iNode ] = listNewNodes.front();
3435 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3436 if ( prevNod[ iNode ] != nextNod [ iNode ])
3437 iNotSameNode = iNode;
3441 sames[nbSame++] = iNode;
3446 //cerr<<" nbSame = "<<nbSame<<endl;
3447 if ( nbSame == nbNodes || nbSame > 2) {
3448 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3449 //INFOS( " Too many same nodes of element " << elem->GetID() );
3453 // if( elem->IsQuadratic() && nbSame>0 ) {
3454 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3458 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3459 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3461 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3462 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3463 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3467 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3468 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3469 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3470 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3472 // check element orientation
3474 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3475 //MESSAGE("Reversed elem " << elem );
3479 std::swap( iBeforeSame, iAfterSame );
3482 // make new elements
3483 const SMDS_MeshElement* lastElem = elem;
3484 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3486 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3487 if(issimple[iNode]) {
3488 nextNod[ iNode ] = *itNN[ iNode ];
3492 if( elem->GetType()==SMDSAbs_Node ) {
3493 // we have to use two nodes
3494 midlNod[ iNode ] = *itNN[ iNode ];
3496 nextNod[ iNode ] = *itNN[ iNode ];
3499 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3500 // we have to use each second node
3502 nextNod[ iNode ] = *itNN[ iNode ];
3506 // we have to use two nodes
3507 midlNod[ iNode ] = *itNN[ iNode ];
3509 nextNod[ iNode ] = *itNN[ iNode ];
3514 SMDS_MeshElement* aNewElem = 0;
3515 if(!elem->IsPoly()) {
3516 switch ( nbNodes ) {
3520 if ( nbSame == 0 ) {
3522 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3524 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3530 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3531 nextNod[ 1 ], nextNod[ 0 ] );
3533 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3534 nextNod[ iNotSameNode ] );
3538 case 3: { // TRIANGLE or quadratic edge
3539 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3541 if ( nbSame == 0 ) // --- pentahedron
3542 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3543 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3545 else if ( nbSame == 1 ) // --- pyramid
3546 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3547 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3548 nextNod[ iSameNode ]);
3550 else // 2 same nodes: --- tetrahedron
3551 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3552 nextNod[ iNotSameNode ]);
3554 else { // quadratic edge
3555 if(nbSame==0) { // quadratic quadrangle
3556 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3557 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3559 else if(nbSame==1) { // quadratic triangle
3561 return; // medium node on axis
3563 else if(sames[0]==0) {
3564 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3565 nextNod[2], midlNod[1], prevNod[2]);
3567 else { // sames[0]==1
3568 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3569 midlNod[0], nextNod[2], prevNod[2]);
3578 case 4: { // QUADRANGLE
3580 if ( nbSame == 0 ) // --- hexahedron
3581 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3582 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3584 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3585 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3586 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3587 nextNod[ iSameNode ]);
3588 newElems.push_back( aNewElem );
3589 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3590 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3591 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3593 else if ( nbSame == 2 ) { // pentahedron
3594 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3595 // iBeforeSame is same too
3596 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3597 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3598 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3600 // iAfterSame is same too
3601 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3602 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3603 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3607 case 6: { // quadratic triangle
3608 // create pentahedron with 15 nodes
3610 if(i0>0) { // reversed case
3611 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3612 nextNod[0], nextNod[2], nextNod[1],
3613 prevNod[5], prevNod[4], prevNod[3],
3614 nextNod[5], nextNod[4], nextNod[3],
3615 midlNod[0], midlNod[2], midlNod[1]);
3617 else { // not reversed case
3618 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3619 nextNod[0], nextNod[1], nextNod[2],
3620 prevNod[3], prevNod[4], prevNod[5],
3621 nextNod[3], nextNod[4], nextNod[5],
3622 midlNod[0], midlNod[1], midlNod[2]);
3625 else if(nbSame==1) {
3626 // 2d order pyramid of 13 nodes
3627 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3628 // int n12,int n23,int n34,int n41,
3629 // int n15,int n25,int n35,int n45, int ID);
3631 int n1,n4,n41,n15,n45;
3632 if(i0>0) { // reversed case
3633 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3634 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3640 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3641 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3646 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3647 nextNod[n4], prevNod[n4], prevNod[n5],
3648 midlNod[n1], nextNod[n41],
3649 midlNod[n4], prevNod[n41],
3650 prevNod[n15], nextNod[n15],
3651 nextNod[n45], prevNod[n45]);
3653 else if(nbSame==2) {
3654 // 2d order tetrahedron of 10 nodes
3655 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3656 // int n12,int n23,int n31,
3657 // int n14,int n24,int n34, int ID);
3658 int n1 = iNotSameNode;
3659 int n2,n3,n12,n23,n31;
3660 if(i0>0) { // reversed case
3661 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3662 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3668 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3669 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3674 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3675 prevNod[n12], prevNod[n23], prevNod[n31],
3676 midlNod[n1], nextNod[n12], nextNod[n31]);
3680 case 8: { // quadratic quadrangle
3682 // create hexahedron with 20 nodes
3683 if(i0>0) { // reversed case
3684 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3685 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3686 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3687 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3688 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3690 else { // not reversed case
3691 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3692 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3693 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3694 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3695 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3698 else if(nbSame==1) {
3699 // --- pyramid + pentahedron - can not be created since it is needed
3700 // additional middle node ot the center of face
3701 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3704 else if(nbSame==2) {
3705 // 2d order Pentahedron with 15 nodes
3706 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3707 // int n12,int n23,int n31,int n45,int n56,int n64,
3708 // int n14,int n25,int n36, int ID);
3710 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3711 // iBeforeSame is same too
3718 // iAfterSame is same too
3724 int n12,n45,n14,n25;
3725 if(i0>0) { //reversed case
3737 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3738 prevNod[n4], prevNod[n5], nextNod[n5],
3739 prevNod[n12], midlNod[n2], nextNod[n12],
3740 prevNod[n45], midlNod[n5], nextNod[n45],
3741 prevNod[n14], prevNod[n25], nextNod[n25]);
3746 // realized for extrusion only
3747 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3748 //vector<int> quantities (nbNodes + 2);
3750 //quantities[0] = nbNodes; // bottom of prism
3751 //for (int inode = 0; inode < nbNodes; inode++) {
3752 // polyedre_nodes[inode] = prevNod[inode];
3755 //quantities[1] = nbNodes; // top of prism
3756 //for (int inode = 0; inode < nbNodes; inode++) {
3757 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3760 //for (int iface = 0; iface < nbNodes; iface++) {
3761 // quantities[iface + 2] = 4;
3762 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3763 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3764 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3765 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3766 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3768 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3775 // realized for extrusion only
3776 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3777 vector<int> quantities (nbNodes + 2);
3779 quantities[0] = nbNodes; // bottom of prism
3780 for (int inode = 0; inode < nbNodes; inode++) {
3781 polyedre_nodes[inode] = prevNod[inode];
3784 quantities[1] = nbNodes; // top of prism
3785 for (int inode = 0; inode < nbNodes; inode++) {
3786 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3789 for (int iface = 0; iface < nbNodes; iface++) {
3790 quantities[iface + 2] = 4;
3791 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3792 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3793 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3794 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3795 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3797 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3801 newElems.push_back( aNewElem );
3802 myLastCreatedElems.Append(aNewElem);
3803 srcElements.Append( elem );
3804 lastElem = aNewElem;
3807 // set new prev nodes
3808 for ( iNode = 0; iNode < nbNodes; iNode++ )
3809 prevNod[ iNode ] = nextNod[ iNode ];
3814 //=======================================================================
3816 * \brief Create 1D and 2D elements around swept elements
3817 * \param mapNewNodes - source nodes and ones generated from them
3818 * \param newElemsMap - source elements and ones generated from them
3819 * \param elemNewNodesMap - nodes generated from each node of each element
3820 * \param elemSet - all swept elements
3821 * \param nbSteps - number of sweeping steps
3822 * \param srcElements - to append elem for each generated element
3824 //=======================================================================
3826 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3827 TElemOfElemListMap & newElemsMap,
3828 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3829 TIDSortedElemSet& elemSet,
3831 SMESH_SequenceOfElemPtr& srcElements)
3833 MESSAGE("makeWalls");
3834 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3835 SMESHDS_Mesh* aMesh = GetMeshDS();
3837 // Find nodes belonging to only one initial element - sweep them to get edges.
3839 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3840 for ( ; nList != mapNewNodes.end(); nList++ ) {
3841 const SMDS_MeshNode* node =
3842 static_cast<const SMDS_MeshNode*>( nList->first );
3843 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3844 int nbInitElems = 0;
3845 const SMDS_MeshElement* el = 0;
3846 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3847 while ( eIt->more() && nbInitElems < 2 ) {
3849 SMDSAbs_ElementType type = el->GetType();
3850 if ( type == SMDSAbs_Volume || type < highType ) continue;
3851 if ( type > highType ) {
3855 if ( elemSet.find(el) != elemSet.end() )
3858 if ( nbInitElems < 2 ) {
3859 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3860 if(!NotCreateEdge) {
3861 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3862 list<const SMDS_MeshElement*> newEdges;
3863 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3868 // Make a ceiling for each element ie an equal element of last new nodes.
3869 // Find free links of faces - make edges and sweep them into faces.
3871 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3872 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3873 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3874 const SMDS_MeshElement* elem = itElem->first;
3875 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3877 if ( elem->GetType() == SMDSAbs_Edge ) {
3878 // create a ceiling edge
3879 if (!elem->IsQuadratic()) {
3880 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3881 vecNewNodes[ 1 ]->second.back())) {
3882 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3883 vecNewNodes[ 1 ]->second.back()));
3884 srcElements.Append( myLastCreatedElems.Last() );
3888 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3889 vecNewNodes[ 1 ]->second.back(),
3890 vecNewNodes[ 2 ]->second.back())) {
3891 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3892 vecNewNodes[ 1 ]->second.back(),
3893 vecNewNodes[ 2 ]->second.back()));
3894 srcElements.Append( myLastCreatedElems.Last() );
3898 if ( elem->GetType() != SMDSAbs_Face )
3901 if(itElem->second.size()==0) continue;
3903 bool hasFreeLinks = false;
3905 TIDSortedElemSet avoidSet;
3906 avoidSet.insert( elem );
3908 set<const SMDS_MeshNode*> aFaceLastNodes;
3909 int iNode, nbNodes = vecNewNodes.size();
3910 if(!elem->IsQuadratic()) {
3911 // loop on the face nodes
3912 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3913 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3914 // look for free links of the face
3915 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3916 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3917 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3918 // check if a link is free
3919 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3920 hasFreeLinks = true;
3921 // make an edge and a ceiling for a new edge
3922 if ( !aMesh->FindEdge( n1, n2 )) {
3923 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3924 srcElements.Append( myLastCreatedElems.Last() );
3926 n1 = vecNewNodes[ iNode ]->second.back();
3927 n2 = vecNewNodes[ iNext ]->second.back();
3928 if ( !aMesh->FindEdge( n1, n2 )) {
3929 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3930 srcElements.Append( myLastCreatedElems.Last() );
3935 else { // elem is quadratic face
3936 int nbn = nbNodes/2;
3937 for ( iNode = 0; iNode < nbn; iNode++ ) {
3938 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3939 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3940 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3941 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3942 // check if a link is free
3943 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3944 hasFreeLinks = true;
3945 // make an edge and a ceiling for a new edge
3947 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3948 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3949 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3950 srcElements.Append( myLastCreatedElems.Last() );
3952 n1 = vecNewNodes[ iNode ]->second.back();
3953 n2 = vecNewNodes[ iNext ]->second.back();
3954 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3955 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3956 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3957 srcElements.Append( myLastCreatedElems.Last() );
3961 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3962 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3966 // sweep free links into faces
3968 if ( hasFreeLinks ) {
3969 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3970 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3972 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3973 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3974 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3975 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3977 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3978 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3980 while ( iVol++ < volNb ) v++;
3981 // find indices of free faces of a volume and their source edges
3982 list< int > freeInd;
3983 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3984 SMDS_VolumeTool vTool( *v );
3985 int iF, nbF = vTool.NbFaces();
3986 for ( iF = 0; iF < nbF; iF ++ ) {
3987 if (vTool.IsFreeFace( iF ) &&
3988 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3989 initNodeSet != faceNodeSet) // except an initial face
3991 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3993 freeInd.push_back( iF );
3994 // find source edge of a free face iF
3995 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3996 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3997 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3998 initNodeSet.begin(), initNodeSet.end(),
3999 commonNodes.begin());
4000 if ( (*v)->IsQuadratic() )
4001 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4003 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4005 if ( !srcEdges.back() )
4007 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4008 << iF << " of volume #" << vTool.ID() << endl;
4013 if ( freeInd.empty() )
4016 // create faces for all steps;
4017 // if such a face has been already created by sweep of edge,
4018 // assure that its orientation is OK
4019 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4021 vTool.SetExternalNormal();
4022 list< int >::iterator ind = freeInd.begin();
4023 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4024 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4026 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4027 int nbn = vTool.NbFaceNodes( *ind );
4029 case 3: { ///// triangle
4030 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4032 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4033 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4035 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4036 aMesh->RemoveElement(f);
4040 case 4: { ///// quadrangle
4041 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4043 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4044 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4046 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4047 aMesh->RemoveElement(f);
4052 if( (*v)->IsQuadratic() ) {
4053 if(nbn==6) { /////// quadratic triangle
4054 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4055 nodes[1], nodes[3], nodes[5] );
4057 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4058 nodes[1], nodes[3], nodes[5]));
4060 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4061 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4062 tmpnodes[0] = nodes[0];
4063 tmpnodes[1] = nodes[2];
4064 tmpnodes[2] = nodes[4];
4065 tmpnodes[3] = nodes[1];
4066 tmpnodes[4] = nodes[3];
4067 tmpnodes[5] = nodes[5];
4068 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069 nodes[1], nodes[3], nodes[5]));
4070 aMesh->RemoveElement(f);
4073 else { /////// quadratic quadrangle
4074 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4075 nodes[1], nodes[3], nodes[5], nodes[7] );
4077 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4078 nodes[1], nodes[3], nodes[5], nodes[7]));
4080 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4081 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4082 tmpnodes[0] = nodes[0];
4083 tmpnodes[1] = nodes[2];
4084 tmpnodes[2] = nodes[4];
4085 tmpnodes[3] = nodes[6];
4086 tmpnodes[4] = nodes[1];
4087 tmpnodes[5] = nodes[3];
4088 tmpnodes[6] = nodes[5];
4089 tmpnodes[7] = nodes[7];
4090 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4091 nodes[1], nodes[3], nodes[5], nodes[7]));
4092 aMesh->RemoveElement(f);
4096 else { //////// polygon
4097 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4098 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4100 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4101 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4103 // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4104 MESSAGE("ChangeElementNodes");
4105 aMesh->ChangeElementNodes( f, nodes, nbn );
4109 while ( srcElements.Length() < myLastCreatedElems.Length() )
4110 srcElements.Append( *srcEdge );
4112 } // loop on free faces
4114 // go to the next volume
4116 while ( iVol++ < nbVolumesByStep ) v++;
4119 } // sweep free links into faces
4121 // Make a ceiling face with a normal external to a volume
4123 SMDS_VolumeTool lastVol( itElem->second.back() );
4125 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4127 lastVol.SetExternalNormal();
4128 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4129 int nbn = lastVol.NbFaceNodes( iF );
4132 if (!hasFreeLinks ||
4133 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4134 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4137 if (!hasFreeLinks ||
4138 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4139 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4142 if(itElem->second.back()->IsQuadratic()) {
4144 if (!hasFreeLinks ||
4145 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4146 nodes[1], nodes[3], nodes[5]) ) {
4147 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4148 nodes[1], nodes[3], nodes[5]));
4152 if (!hasFreeLinks ||
4153 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4154 nodes[1], nodes[3], nodes[5], nodes[7]) )
4155 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4156 nodes[1], nodes[3], nodes[5], nodes[7]));
4160 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4161 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4162 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4166 while ( srcElements.Length() < myLastCreatedElems.Length() )
4167 srcElements.Append( myLastCreatedElems.Last() );
4169 } // loop on swept elements
4172 //=======================================================================
4173 //function : RotationSweep
4175 //=======================================================================
4177 SMESH_MeshEditor::PGroupIDs
4178 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4179 const gp_Ax1& theAxis,
4180 const double theAngle,
4181 const int theNbSteps,
4182 const double theTol,
4183 const bool theMakeGroups,
4184 const bool theMakeWalls)
4186 myLastCreatedElems.Clear();
4187 myLastCreatedNodes.Clear();
4189 // source elements for each generated one
4190 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4192 MESSAGE( "RotationSweep()");
4194 aTrsf.SetRotation( theAxis, theAngle );
4196 aTrsf2.SetRotation( theAxis, theAngle/2. );
4198 gp_Lin aLine( theAxis );
4199 double aSqTol = theTol * theTol;
4201 SMESHDS_Mesh* aMesh = GetMeshDS();
4203 TNodeOfNodeListMap mapNewNodes;
4204 TElemOfVecOfNnlmiMap mapElemNewNodes;
4205 TElemOfElemListMap newElemsMap;
4208 TIDSortedElemSet::iterator itElem;
4209 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4210 const SMDS_MeshElement* elem = *itElem;
4211 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4213 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4214 newNodesItVec.reserve( elem->NbNodes() );
4216 // loop on elem nodes
4217 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4218 while ( itN->more() ) {
4219 // check if a node has been already sweeped
4220 const SMDS_MeshNode* node = cast2Node( itN->next() );
4222 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4224 aXYZ.Coord( coord[0], coord[1], coord[2] );
4225 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4227 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4228 if ( nIt == mapNewNodes.end() ) {
4229 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4230 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4233 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4235 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4236 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4237 const SMDS_MeshNode * newNode = node;
4238 for ( int i = 0; i < theNbSteps; i++ ) {
4240 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4242 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4243 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4244 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4245 myLastCreatedNodes.Append(newNode);
4246 srcNodes.Append( node );
4247 listNewNodes.push_back( newNode );
4248 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4249 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4252 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4254 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4255 myLastCreatedNodes.Append(newNode);
4256 srcNodes.Append( node );
4257 listNewNodes.push_back( newNode );
4260 listNewNodes.push_back( newNode );
4261 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4262 listNewNodes.push_back( newNode );
4269 // if current elem is quadratic and current node is not medium
4270 // we have to check - may be it is needed to insert additional nodes
4271 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4272 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4273 if(listNewNodes.size()==theNbSteps) {
4274 listNewNodes.clear();
4276 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4278 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4279 const SMDS_MeshNode * newNode = node;
4281 for(int i = 0; i<theNbSteps; i++) {
4282 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4283 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4284 cout<<" 3 AddNode: "<<newNode;
4285 myLastCreatedNodes.Append(newNode);
4286 listNewNodes.push_back( newNode );
4287 srcNodes.Append( node );
4288 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4289 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4290 cout<<" 4 AddNode: "<<newNode;
4291 myLastCreatedNodes.Append(newNode);
4292 srcNodes.Append( node );
4293 listNewNodes.push_back( newNode );
4297 listNewNodes.push_back( newNode );
4303 newNodesItVec.push_back( nIt );
4305 // make new elements
4306 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4310 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4312 PGroupIDs newGroupIDs;
4313 if ( theMakeGroups )
4314 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4320 //=======================================================================
4321 //function : CreateNode
4323 //=======================================================================
4324 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4327 const double tolnode,
4328 SMESH_SequenceOfNode& aNodes)
4330 myLastCreatedElems.Clear();
4331 myLastCreatedNodes.Clear();
4334 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4336 // try to search in sequence of existing nodes
4337 // if aNodes.Length()>0 we 'nave to use given sequence
4338 // else - use all nodes of mesh
4339 if(aNodes.Length()>0) {
4341 for(i=1; i<=aNodes.Length(); i++) {
4342 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4343 if(P1.Distance(P2)<tolnode)
4344 return aNodes.Value(i);
4348 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4349 while(itn->more()) {
4350 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4351 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4352 if(P1.Distance(P2)<tolnode)
4357 // create new node and return it
4358 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4359 myLastCreatedNodes.Append(NewNode);
4364 //=======================================================================
4365 //function : ExtrusionSweep
4367 //=======================================================================
4369 SMESH_MeshEditor::PGroupIDs
4370 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4371 const gp_Vec& theStep,
4372 const int theNbSteps,
4373 TElemOfElemListMap& newElemsMap,
4374 const bool theMakeGroups,
4376 const double theTolerance)
4378 ExtrusParam aParams;
4379 aParams.myDir = gp_Dir(theStep);
4380 aParams.myNodes.Clear();
4381 aParams.mySteps = new TColStd_HSequenceOfReal;
4383 for(i=1; i<=theNbSteps; i++)
4384 aParams.mySteps->Append(theStep.Magnitude());
4387 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4391 //=======================================================================
4392 //function : ExtrusionSweep
4394 //=======================================================================
4396 SMESH_MeshEditor::PGroupIDs
4397 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4398 ExtrusParam& theParams,
4399 TElemOfElemListMap& newElemsMap,
4400 const bool theMakeGroups,
4402 const double theTolerance)
4404 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4405 myLastCreatedElems.Clear();
4406 myLastCreatedNodes.Clear();
4408 // source elements for each generated one
4409 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4411 SMESHDS_Mesh* aMesh = GetMeshDS();
4413 int nbsteps = theParams.mySteps->Length();
4415 TNodeOfNodeListMap mapNewNodes;
4416 //TNodeOfNodeVecMap mapNewNodes;
4417 TElemOfVecOfNnlmiMap mapElemNewNodes;
4418 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4421 TIDSortedElemSet::iterator itElem;
4422 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4423 // check element type
4424 const SMDS_MeshElement* elem = *itElem;
4425 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4428 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4429 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4430 newNodesItVec.reserve( elem->NbNodes() );
4432 // loop on elem nodes
4433 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4434 while ( itN->more() )
4436 // check if a node has been already sweeped
4437 const SMDS_MeshNode* node = cast2Node( itN->next() );
4438 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4439 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4440 if ( nIt == mapNewNodes.end() ) {
4441 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4442 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4443 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4444 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4445 //vecNewNodes.reserve(nbsteps);
4448 double coord[] = { node->X(), node->Y(), node->Z() };
4449 //int nbsteps = theParams.mySteps->Length();
4450 for ( int i = 0; i < nbsteps; i++ ) {
4451 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4452 // create additional node
4453 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4454 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4455 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4456 if( theFlags & EXTRUSION_FLAG_SEW ) {
4457 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4458 theTolerance, theParams.myNodes);
4459 listNewNodes.push_back( newNode );
4462 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4463 myLastCreatedNodes.Append(newNode);
4464 srcNodes.Append( node );
4465 listNewNodes.push_back( newNode );
4468 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4469 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4470 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4471 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4472 if( theFlags & EXTRUSION_FLAG_SEW ) {
4473 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4474 theTolerance, theParams.myNodes);
4475 listNewNodes.push_back( newNode );
4476 //vecNewNodes[i]=newNode;
4479 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4480 myLastCreatedNodes.Append(newNode);
4481 srcNodes.Append( node );
4482 listNewNodes.push_back( newNode );
4483 //vecNewNodes[i]=newNode;
4488 // if current elem is quadratic and current node is not medium
4489 // we have to check - may be it is needed to insert additional nodes
4490 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4491 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4492 if(listNewNodes.size()==nbsteps) {
4493 listNewNodes.clear();
4494 double coord[] = { node->X(), node->Y(), node->Z() };
4495 for ( int i = 0; i < nbsteps; i++ ) {
4496 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4497 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4498 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4499 if( theFlags & EXTRUSION_FLAG_SEW ) {
4500 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4501 theTolerance, theParams.myNodes);
4502 listNewNodes.push_back( newNode );
4505 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4506 myLastCreatedNodes.Append(newNode);
4507 srcNodes.Append( node );
4508 listNewNodes.push_back( newNode );
4510 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4511 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4512 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4513 if( theFlags & EXTRUSION_FLAG_SEW ) {
4514 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4515 theTolerance, theParams.myNodes);
4516 listNewNodes.push_back( newNode );
4519 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4520 myLastCreatedNodes.Append(newNode);
4521 srcNodes.Append( node );
4522 listNewNodes.push_back( newNode );
4528 newNodesItVec.push_back( nIt );
4530 // make new elements
4531 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4534 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4535 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4537 PGroupIDs newGroupIDs;
4538 if ( theMakeGroups )
4539 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4545 //=======================================================================
4546 //class : SMESH_MeshEditor_PathPoint
4547 //purpose : auxiliary class
4548 //=======================================================================
4549 class SMESH_MeshEditor_PathPoint {
4551 SMESH_MeshEditor_PathPoint() {
4552 myPnt.SetCoord(99., 99., 99.);
4553 myTgt.SetCoord(1.,0.,0.);
4557 void SetPnt(const gp_Pnt& aP3D){
4560 void SetTangent(const gp_Dir& aTgt){
4563 void SetAngle(const double& aBeta){
4566 void SetParameter(const double& aPrm){
4569 const gp_Pnt& Pnt()const{
4572 const gp_Dir& Tangent()const{
4575 double Angle()const{
4578 double Parameter()const{
4590 //=======================================================================
4591 //function : ExtrusionAlongTrack
4593 //=======================================================================
4594 SMESH_MeshEditor::Extrusion_Error
4595 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4596 SMESH_subMesh* theTrack,
4597 const SMDS_MeshNode* theN1,
4598 const bool theHasAngles,
4599 list<double>& theAngles,
4600 const bool theLinearVariation,
4601 const bool theHasRefPoint,
4602 const gp_Pnt& theRefPoint,
4603 const bool theMakeGroups)
4605 MESSAGE("ExtrusionAlongTrack");
4606 myLastCreatedElems.Clear();
4607 myLastCreatedNodes.Clear();
4610 std::list<double> aPrms;
4611 TIDSortedElemSet::iterator itElem;
4614 TopoDS_Edge aTrackEdge;
4615 TopoDS_Vertex aV1, aV2;
4617 SMDS_ElemIteratorPtr aItE;
4618 SMDS_NodeIteratorPtr aItN;
4619 SMDSAbs_ElementType aTypeE;
4621 TNodeOfNodeListMap mapNewNodes;
4624 aNbE = theElements.size();
4627 return EXTR_NO_ELEMENTS;
4629 // 1.1 Track Pattern
4632 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4634 aItE = pSubMeshDS->GetElements();
4635 while ( aItE->more() ) {
4636 const SMDS_MeshElement* pE = aItE->next();
4637 aTypeE = pE->GetType();
4638 // Pattern must contain links only
4639 if ( aTypeE != SMDSAbs_Edge )
4640 return EXTR_PATH_NOT_EDGE;
4643 list<SMESH_MeshEditor_PathPoint> fullList;
4645 const TopoDS_Shape& aS = theTrack->GetSubShape();
4646 // Sub shape for the Pattern must be an Edge or Wire
4647 if( aS.ShapeType() == TopAbs_EDGE ) {
4648 aTrackEdge = TopoDS::Edge( aS );
4649 // the Edge must not be degenerated
4650 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4651 return EXTR_BAD_PATH_SHAPE;
4652 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4653 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4654 const SMDS_MeshNode* aN1 = aItN->next();
4655 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4656 const SMDS_MeshNode* aN2 = aItN->next();
4657 // starting node must be aN1 or aN2
4658 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4659 return EXTR_BAD_STARTING_NODE;
4660 aItN = pSubMeshDS->GetNodes();
4661 while ( aItN->more() ) {
4662 const SMDS_MeshNode* pNode = aItN->next();
4663 const SMDS_EdgePosition* pEPos =
4664 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4665 double aT = pEPos->GetUParameter();
4666 aPrms.push_back( aT );
4668 //Extrusion_Error err =
4669 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4671 else if( aS.ShapeType() == TopAbs_WIRE ) {
4672 list< SMESH_subMesh* > LSM;
4673 TopTools_SequenceOfShape Edges;
4674 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4675 while(itSM->more()) {
4676 SMESH_subMesh* SM = itSM->next();
4678 const TopoDS_Shape& aS = SM->GetSubShape();
4681 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4682 int startNid = theN1->GetID();
4683 TColStd_MapOfInteger UsedNums;
4684 int NbEdges = Edges.Length();
4686 for(; i<=NbEdges; i++) {
4688 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4689 for(; itLSM!=LSM.end(); itLSM++) {
4691 if(UsedNums.Contains(k)) continue;
4692 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4693 SMESH_subMesh* locTrack = *itLSM;
4694 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4695 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4696 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4697 const SMDS_MeshNode* aN1 = aItN->next();
4698 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4699 const SMDS_MeshNode* aN2 = aItN->next();
4700 // starting node must be aN1 or aN2
4701 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4702 // 2. Collect parameters on the track edge
4704 aItN = locMeshDS->GetNodes();
4705 while ( aItN->more() ) {
4706 const SMDS_MeshNode* pNode = aItN->next();
4707 const SMDS_EdgePosition* pEPos =
4708 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4709 double aT = pEPos->GetUParameter();
4710 aPrms.push_back( aT );
4712 list<SMESH_MeshEditor_PathPoint> LPP;
4713 //Extrusion_Error err =
4714 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4715 LLPPs.push_back(LPP);
4717 // update startN for search following egde
4718 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4719 else startNid = aN1->GetID();
4723 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4724 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4725 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4726 for(; itPP!=firstList.end(); itPP++) {
4727 fullList.push_back( *itPP );
4729 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4730 fullList.pop_back();
4732 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4733 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4734 itPP = currList.begin();
4735 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4736 gp_Dir D1 = PP1.Tangent();
4737 gp_Dir D2 = PP2.Tangent();
4738 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4739 (D1.Z()+D2.Z())/2 ) );
4740 PP1.SetTangent(Dnew);
4741 fullList.push_back(PP1);
4743 for(; itPP!=firstList.end(); itPP++) {
4744 fullList.push_back( *itPP );
4746 PP1 = fullList.back();
4747 fullList.pop_back();
4749 // if wire not closed
4750 fullList.push_back(PP1);
4754 return EXTR_BAD_PATH_SHAPE;
4757 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4758 theHasRefPoint, theRefPoint, theMakeGroups);
4762 //=======================================================================
4763 //function : ExtrusionAlongTrack
4765 //=======================================================================
4766 SMESH_MeshEditor::Extrusion_Error
4767 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4768 SMESH_Mesh* theTrack,
4769 const SMDS_MeshNode* theN1,
4770 const bool theHasAngles,
4771 list<double>& theAngles,
4772 const bool theLinearVariation,
4773 const bool theHasRefPoint,
4774 const gp_Pnt& theRefPoint,
4775 const bool theMakeGroups)
4777 myLastCreatedElems.Clear();
4778 myLastCreatedNodes.Clear();
4781 std::list<double> aPrms;
4782 TIDSortedElemSet::iterator itElem;
4785 TopoDS_Edge aTrackEdge;
4786 TopoDS_Vertex aV1, aV2;
4788 SMDS_ElemIteratorPtr aItE;
4789 SMDS_NodeIteratorPtr aItN;
4790 SMDSAbs_ElementType aTypeE;
4792 TNodeOfNodeListMap mapNewNodes;
4795 aNbE = theElements.size();
4798 return EXTR_NO_ELEMENTS;
4800 // 1.1 Track Pattern
4803 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4805 aItE = pMeshDS->elementsIterator();
4806 while ( aItE->more() ) {
4807 const SMDS_MeshElement* pE = aItE->next();
4808 aTypeE = pE->GetType();
4809 // Pattern must contain links only
4810 if ( aTypeE != SMDSAbs_Edge )
4811 return EXTR_PATH_NOT_EDGE;
4814 list<SMESH_MeshEditor_PathPoint> fullList;
4816 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4817 // Sub shape for the Pattern must be an Edge or Wire
4818 if( aS.ShapeType() == TopAbs_EDGE ) {
4819 aTrackEdge = TopoDS::Edge( aS );
4820 // the Edge must not be degenerated
4821 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4822 return EXTR_BAD_PATH_SHAPE;
4823 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4824 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4825 const SMDS_MeshNode* aN1 = aItN->next();
4826 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4827 const SMDS_MeshNode* aN2 = aItN->next();
4828 // starting node must be aN1 or aN2
4829 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4830 return EXTR_BAD_STARTING_NODE;
4831 aItN = pMeshDS->nodesIterator();
4832 while ( aItN->more() ) {
4833 const SMDS_MeshNode* pNode = aItN->next();
4834 if( pNode==aN1 || pNode==aN2 ) continue;
4835 const SMDS_EdgePosition* pEPos =
4836 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4837 double aT = pEPos->GetUParameter();
4838 aPrms.push_back( aT );
4840 //Extrusion_Error err =
4841 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4843 else if( aS.ShapeType() == TopAbs_WIRE ) {
4844 list< SMESH_subMesh* > LSM;
4845 TopTools_SequenceOfShape Edges;
4846 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4847 for(; eExp.More(); eExp.Next()) {
4848 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4849 if( BRep_Tool::Degenerated(E) ) continue;
4850 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4856 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4857 int startNid = theN1->GetID();
4858 TColStd_MapOfInteger UsedNums;
4859 int NbEdges = Edges.Length();
4861 for(; i<=NbEdges; i++) {
4863 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4864 for(; itLSM!=LSM.end(); itLSM++) {
4866 if(UsedNums.Contains(k)) continue;
4867 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4868 SMESH_subMesh* locTrack = *itLSM;
4869 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4870 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4871 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4872 const SMDS_MeshNode* aN1 = aItN->next();
4873 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4874 const SMDS_MeshNode* aN2 = aItN->next();
4875 // starting node must be aN1 or aN2
4876 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4877 // 2. Collect parameters on the track edge
4879 aItN = locMeshDS->GetNodes();
4880 while ( aItN->more() ) {
4881 const SMDS_MeshNode* pNode = aItN->next();
4882 const SMDS_EdgePosition* pEPos =
4883 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4884 double aT = pEPos->GetUParameter();
4885 aPrms.push_back( aT );
4887 list<SMESH_MeshEditor_PathPoint> LPP;
4888 //Extrusion_Error err =
4889 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4890 LLPPs.push_back(LPP);
4892 // update startN for search following egde
4893 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4894 else startNid = aN1->GetID();
4898 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4899 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4900 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4901 for(; itPP!=firstList.end(); itPP++) {
4902 fullList.push_back( *itPP );
4904 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4905 fullList.pop_back();
4907 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4908 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4909 itPP = currList.begin();
4910 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4911 gp_Pnt P1 = PP1.Pnt();
4912 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4913 gp_Pnt P2 = PP2.Pnt();
4914 gp_Dir D1 = PP1.Tangent();
4915 gp_Dir D2 = PP2.Tangent();
4916 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4917 (D1.Z()+D2.Z())/2 ) );
4918 PP1.SetTangent(Dnew);
4919 fullList.push_back(PP1);
4921 for(; itPP!=currList.end(); itPP++) {
4922 fullList.push_back( *itPP );
4924 PP1 = fullList.back();
4925 fullList.pop_back();
4927 // if wire not closed
4928 fullList.push_back(PP1);
4932 return EXTR_BAD_PATH_SHAPE;
4935 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4936 theHasRefPoint, theRefPoint, theMakeGroups);
4940 //=======================================================================
4941 //function : MakeEdgePathPoints
4942 //purpose : auxilary for ExtrusionAlongTrack
4943 //=======================================================================
4944 SMESH_MeshEditor::Extrusion_Error
4945 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4946 const TopoDS_Edge& aTrackEdge,
4948 list<SMESH_MeshEditor_PathPoint>& LPP)
4950 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4952 aTolVec2=aTolVec*aTolVec;
4954 TopoDS_Vertex aV1, aV2;
4955 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4956 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4957 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4958 // 2. Collect parameters on the track edge
4959 aPrms.push_front( aT1 );
4960 aPrms.push_back( aT2 );
4963 if( FirstIsStart ) {
4974 SMESH_MeshEditor_PathPoint aPP;
4975 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4976 std::list<double>::iterator aItD = aPrms.begin();
4977 for(; aItD != aPrms.end(); ++aItD) {
4981 aC3D->D1( aT, aP3D, aVec );
4982 aL2 = aVec.SquareMagnitude();
4983 if ( aL2 < aTolVec2 )
4984 return EXTR_CANT_GET_TANGENT;
4985 gp_Dir aTgt( aVec );
4987 aPP.SetTangent( aTgt );
4988 aPP.SetParameter( aT );
4995 //=======================================================================
4996 //function : MakeExtrElements
4997 //purpose : auxilary for ExtrusionAlongTrack
4998 //=======================================================================
4999 SMESH_MeshEditor::Extrusion_Error
5000 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5001 list<SMESH_MeshEditor_PathPoint>& fullList,
5002 const bool theHasAngles,
5003 list<double>& theAngles,
5004 const bool theLinearVariation,
5005 const bool theHasRefPoint,
5006 const gp_Pnt& theRefPoint,
5007 const bool theMakeGroups)
5009 MESSAGE("MakeExtrElements");
5010 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5011 int aNbTP = fullList.size();
5012 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5014 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5015 LinearAngleVariation(aNbTP-1, theAngles);
5017 vector<double> aAngles( aNbTP );
5019 for(; j<aNbTP; ++j) {
5022 if ( theHasAngles ) {
5024 std::list<double>::iterator aItD = theAngles.begin();
5025 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5027 aAngles[j] = anAngle;
5030 // fill vector of path points with angles
5031 //aPPs.resize(fullList.size());
5033 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5034 for(; itPP!=fullList.end(); itPP++) {
5036 SMESH_MeshEditor_PathPoint PP = *itPP;
5037 PP.SetAngle(aAngles[j]);
5041 TNodeOfNodeListMap mapNewNodes;
5042 TElemOfVecOfNnlmiMap mapElemNewNodes;
5043 TElemOfElemListMap newElemsMap;
5044 TIDSortedElemSet::iterator itElem;
5047 SMDSAbs_ElementType aTypeE;
5048 // source elements for each generated one
5049 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5051 // 3. Center of rotation aV0
5052 gp_Pnt aV0 = theRefPoint;
5054 if ( !theHasRefPoint ) {
5056 aGC.SetCoord( 0.,0.,0. );
5058 itElem = theElements.begin();
5059 for ( ; itElem != theElements.end(); itElem++ ) {
5060 const SMDS_MeshElement* elem = *itElem;
5062 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5063 while ( itN->more() ) {
5064 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5069 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5070 list<const SMDS_MeshNode*> aLNx;
5071 mapNewNodes[node] = aLNx;
5073 gp_XYZ aXYZ( aX, aY, aZ );
5081 } // if (!theHasRefPoint) {
5082 mapNewNodes.clear();
5084 // 4. Processing the elements
5085 SMESHDS_Mesh* aMesh = GetMeshDS();
5087 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5088 // check element type
5089 const SMDS_MeshElement* elem = *itElem;
5090 aTypeE = elem->GetType();
5091 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5094 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5095 newNodesItVec.reserve( elem->NbNodes() );
5097 // loop on elem nodes
5099 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5100 while ( itN->more() )
5103 // check if a node has been already processed
5104 const SMDS_MeshNode* node =
5105 static_cast<const SMDS_MeshNode*>( itN->next() );
5106 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5107 if ( nIt == mapNewNodes.end() ) {
5108 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5109 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5112 aX = node->X(); aY = node->Y(); aZ = node->Z();
5114 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5115 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5116 gp_Ax1 anAx1, anAxT1T0;
5117 gp_Dir aDT1x, aDT0x, aDT1T0;
5122 aPN0.SetCoord(aX, aY, aZ);
5124 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5126 aDT0x= aPP0.Tangent();
5127 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5129 for ( j = 1; j < aNbTP; ++j ) {
5130 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5132 aDT1x = aPP1.Tangent();
5133 aAngle1x = aPP1.Angle();
5135 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5137 gp_Vec aV01x( aP0x, aP1x );
5138 aTrsf.SetTranslation( aV01x );
5141 aV1x = aV0x.Transformed( aTrsf );
5142 aPN1 = aPN0.Transformed( aTrsf );
5144 // rotation 1 [ T1,T0 ]
5145 aAngleT1T0=-aDT1x.Angle( aDT0x );
5146 if (fabs(aAngleT1T0) > aTolAng) {
5148 anAxT1T0.SetLocation( aV1x );
5149 anAxT1T0.SetDirection( aDT1T0 );
5150 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5152 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5156 if ( theHasAngles ) {
5157 anAx1.SetLocation( aV1x );
5158 anAx1.SetDirection( aDT1x );
5159 aTrsfRot.SetRotation( anAx1, aAngle1x );
5161 aPN1 = aPN1.Transformed( aTrsfRot );
5165 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5166 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5167 // create additional node
5168 double x = ( aPN1.X() + aPN0.X() )/2.;
5169 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5170 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5171 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5172 myLastCreatedNodes.Append(newNode);
5173 srcNodes.Append( node );
5174 listNewNodes.push_back( newNode );
5179 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5180 myLastCreatedNodes.Append(newNode);
5181 srcNodes.Append( node );
5182 listNewNodes.push_back( newNode );
5192 // if current elem is quadratic and current node is not medium
5193 // we have to check - may be it is needed to insert additional nodes
5194 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5195 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5196 if(listNewNodes.size()==aNbTP-1) {
5197 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5198 gp_XYZ P(node->X(), node->Y(), node->Z());
5199 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5201 for(i=0; i<aNbTP-1; i++) {
5202 const SMDS_MeshNode* N = *it;
5203 double x = ( N->X() + P.X() )/2.;
5204 double y = ( N->Y() + P.Y() )/2.;
5205 double z = ( N->Z() + P.Z() )/2.;
5206 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5207 srcNodes.Append( node );
5208 myLastCreatedNodes.Append(newN);
5211 P = gp_XYZ(N->X(),N->Y(),N->Z());
5213 listNewNodes.clear();
5214 for(i=0; i<2*(aNbTP-1); i++) {
5215 listNewNodes.push_back(aNodes[i]);
5221 newNodesItVec.push_back( nIt );
5223 // make new elements
5224 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5225 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5226 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5229 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5231 if ( theMakeGroups )
5232 generateGroups( srcNodes, srcElems, "extruded");
5238 //=======================================================================
5239 //function : LinearAngleVariation
5240 //purpose : auxilary for ExtrusionAlongTrack
5241 //=======================================================================
5242 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5243 list<double>& Angles)
5245 int nbAngles = Angles.size();
5246 if( nbSteps > nbAngles ) {
5247 vector<double> theAngles(nbAngles);
5248 list<double>::iterator it = Angles.begin();
5250 for(; it!=Angles.end(); it++) {
5252 theAngles[i] = (*it);
5255 double rAn2St = double( nbAngles ) / double( nbSteps );
5256 double angPrev = 0, angle;
5257 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5258 double angCur = rAn2St * ( iSt+1 );
5259 double angCurFloor = floor( angCur );
5260 double angPrevFloor = floor( angPrev );
5261 if ( angPrevFloor == angCurFloor )
5262 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5264 int iP = int( angPrevFloor );
5265 double angPrevCeil = ceil(angPrev);
5266 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5268 int iC = int( angCurFloor );
5269 if ( iC < nbAngles )
5270 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5272 iP = int( angPrevCeil );
5274 angle += theAngles[ iC ];
5276 res.push_back(angle);
5281 for(; it!=res.end(); it++)
5282 Angles.push_back( *it );
5287 //================================================================================
5289 * \brief Move or copy theElements applying theTrsf to their nodes
5290 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5291 * \param theTrsf - transformation to apply
5292 * \param theCopy - if true, create translated copies of theElems
5293 * \param theMakeGroups - if true and theCopy, create translated groups
5294 * \param theTargetMesh - mesh to copy translated elements into
5295 * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5297 //================================================================================
5299 SMESH_MeshEditor::PGroupIDs
5300 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5301 const gp_Trsf& theTrsf,
5303 const bool theMakeGroups,
5304 SMESH_Mesh* theTargetMesh)
5306 myLastCreatedElems.Clear();
5307 myLastCreatedNodes.Clear();
5309 bool needReverse = false;
5310 string groupPostfix;
5311 switch ( theTrsf.Form() ) {
5316 groupPostfix = "mirrored";
5319 groupPostfix = "rotated";
5321 case gp_Translation:
5322 groupPostfix = "translated";
5325 case gp_CompoundTrsf: // different scale by axis
5326 groupPostfix = "scaled";
5329 needReverse = false;
5330 groupPostfix = "transformed";
5333 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5334 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5335 SMESHDS_Mesh* aMesh = GetMeshDS();
5338 // map old node to new one
5339 TNodeNodeMap nodeMap;
5341 // elements sharing moved nodes; those of them which have all
5342 // nodes mirrored but are not in theElems are to be reversed
5343 TIDSortedElemSet inverseElemSet;
5345 // source elements for each generated one
5346 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5348 // // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5349 // list<SMDS_MeshNode> orphanCopy; // copies of orphan nodes
5350 // vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5352 // if ( theElems.empty() ) // transform the whole mesh
5354 // // add all elements
5355 // SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5356 // while ( eIt->more() ) theElems.insert( eIt->next() );
5357 // // add orphan nodes
5358 // SMDS_MeshElementIDFactory idFactory;
5359 // SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5360 // while ( nIt->more() )
5362 // const SMDS_MeshNode* node = nIt->next();
5363 // if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5365 // // node was not inserted into theElems because an element with the same ID
5366 // // is already there. As a work around we insert a copy of node with
5367 // // an ID = -<index in orphanNode>
5368 // orphanCopy.push_back( *node ); // copy node
5369 // SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5370 // int uniqueID = -orphanNode.size();
5371 // orphanNode.push_back( node );
5372 // idFactory.BindID( uniqueID, nodeCopy );
5373 // theElems.insert( nodeCopy );
5377 // loop on theElems to transorm nodes
5378 TIDSortedElemSet::iterator itElem;
5379 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5380 const SMDS_MeshElement* elem = *itElem;
5384 // loop on elem nodes
5385 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5386 while ( itN->more() ) {
5388 const SMDS_MeshNode* node = cast2Node( itN->next() );
5389 // if ( node->GetID() < 0 )
5390 // node = orphanNode[ -node->GetID() ];
5391 // check if a node has been already transformed
5392 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5393 nodeMap.insert( make_pair ( node, node ));
5394 if ( !n2n_isnew.second )
5398 coord[0] = node->X();
5399 coord[1] = node->Y();
5400 coord[2] = node->Z();
5401 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5402 if ( theTargetMesh ) {
5403 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5404 n2n_isnew.first->second = newNode;
5405 myLastCreatedNodes.Append(newNode);
5406 srcNodes.Append( node );
5408 else if ( theCopy ) {
5409 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5410 n2n_isnew.first->second = newNode;
5411 myLastCreatedNodes.Append(newNode);
5412 srcNodes.Append( node );
5415 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5416 // node position on shape becomes invalid
5417 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5418 ( SMDS_SpacePosition::originSpacePosition() );
5421 // keep inverse elements
5422 if ( !theCopy && !theTargetMesh && needReverse ) {
5423 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5424 while ( invElemIt->more() ) {
5425 const SMDS_MeshElement* iel = invElemIt->next();
5426 inverseElemSet.insert( iel );
5432 // either create new elements or reverse mirrored ones
5433 if ( !theCopy && !needReverse && !theTargetMesh )
5436 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5437 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5438 theElems.insert( *invElemIt );
5440 // replicate or reverse elements
5441 // TODO revoir ordre reverse vtk
5443 REV_TETRA = 0, // = nbNodes - 4
5444 REV_PYRAMID = 1, // = nbNodes - 4
5445 REV_PENTA = 2, // = nbNodes - 4
5447 REV_HEXA = 4, // = nbNodes - 4
5451 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5452 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5453 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5454 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5455 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5456 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5459 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5461 const SMDS_MeshElement* elem = *itElem;
5462 if ( !elem || elem->GetType() == SMDSAbs_Node )
5465 int nbNodes = elem->NbNodes();
5466 int elemType = elem->GetType();
5468 if (elem->IsPoly()) {
5469 // Polygon or Polyhedral Volume
5470 switch ( elemType ) {
5473 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5475 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5476 while (itN->more()) {
5477 const SMDS_MeshNode* node =
5478 static_cast<const SMDS_MeshNode*>(itN->next());
5479 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5480 if (nodeMapIt == nodeMap.end())
5481 break; // not all nodes transformed
5483 // reverse mirrored faces and volumes
5484 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5486 poly_nodes[iNode] = (*nodeMapIt).second;
5490 if ( iNode != nbNodes )
5491 continue; // not all nodes transformed
5493 if ( theTargetMesh ) {
5494 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5495 srcElems.Append( elem );
5497 else if ( theCopy ) {
5498 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5499 srcElems.Append( elem );
5502 aMesh->ChangePolygonNodes(elem, poly_nodes);
5506 case SMDSAbs_Volume:
5508 // ATTENTION: Reversing is not yet done!!!
5509 const SMDS_VtkVolume* aPolyedre =
5510 dynamic_cast<const SMDS_VtkVolume*>( elem );
5512 MESSAGE("Warning: bad volumic element");
5516 vector<const SMDS_MeshNode*> poly_nodes;
5517 vector<int> quantities;
5519 bool allTransformed = true;
5520 int nbFaces = aPolyedre->NbFaces();
5521 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5522 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5523 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5524 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5525 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5526 if (nodeMapIt == nodeMap.end()) {
5527 allTransformed = false; // not all nodes transformed
5529 poly_nodes.push_back((*nodeMapIt).second);
5532 quantities.push_back(nbFaceNodes);
5534 if ( !allTransformed )
5535 continue; // not all nodes transformed
5537 if ( theTargetMesh ) {
5538 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5539 srcElems.Append( elem );
5541 else if ( theCopy ) {
5542 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5543 srcElems.Append( elem );
5546 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5556 int* i = index[ FORWARD ];
5557 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5558 if ( elemType == SMDSAbs_Face )
5559 i = index[ REV_FACE ];
5561 i = index[ nbNodes - 4 ];
5563 if(elem->IsQuadratic()) {
5564 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5567 if(nbNodes==3) { // quadratic edge
5568 static int anIds[] = {1,0,2};
5571 else if(nbNodes==6) { // quadratic triangle
5572 static int anIds[] = {0,2,1,5,4,3};
5575 else if(nbNodes==8) { // quadratic quadrangle
5576 static int anIds[] = {0,3,2,1,7,6,5,4};
5579 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5580 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5583 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5584 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5587 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5588 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5591 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5592 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5598 // find transformed nodes
5599 vector<const SMDS_MeshNode*> nodes(nbNodes);
5601 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5602 while ( itN->more() ) {
5603 const SMDS_MeshNode* node =
5604 static_cast<const SMDS_MeshNode*>( itN->next() );
5605 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5606 if ( nodeMapIt == nodeMap.end() )
5607 break; // not all nodes transformed
5608 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5610 if ( iNode != nbNodes )
5611 continue; // not all nodes transformed
5613 if ( theTargetMesh ) {
5614 if ( SMDS_MeshElement* copy =
5615 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5616 myLastCreatedElems.Append( copy );
5617 srcElems.Append( elem );
5620 else if ( theCopy ) {
5621 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5622 srcElems.Append( elem );
5625 // reverse element as it was reversed by transformation
5627 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5631 PGroupIDs newGroupIDs;
5633 if ( theMakeGroups && theCopy ||
5634 theMakeGroups && theTargetMesh )
5635 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5641 ////=======================================================================
5642 ////function : Scale
5644 ////=======================================================================
5646 //SMESH_MeshEditor::PGroupIDs
5647 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5648 // const gp_Pnt& thePoint,
5649 // const std::list<double>& theScaleFact,
5650 // const bool theCopy,
5651 // const bool theMakeGroups,
5652 // SMESH_Mesh* theTargetMesh)
5654 // MESSAGE("Scale");
5655 // myLastCreatedElems.Clear();
5656 // myLastCreatedNodes.Clear();
5658 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5659 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5660 // SMESHDS_Mesh* aMesh = GetMeshDS();
5662 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5663 // std::list<double>::const_iterator itS = theScaleFact.begin();
5665 // if(theScaleFact.size()==1) {
5669 // if(theScaleFact.size()==2) {
5674 // if(theScaleFact.size()>2) {
5681 // // map old node to new one
5682 // TNodeNodeMap nodeMap;
5684 // // elements sharing moved nodes; those of them which have all
5685 // // nodes mirrored but are not in theElems are to be reversed
5686 // TIDSortedElemSet inverseElemSet;
5688 // // source elements for each generated one
5689 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5691 // // loop on theElems
5692 // TIDSortedElemSet::iterator itElem;
5693 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5694 // const SMDS_MeshElement* elem = *itElem;
5698 // // loop on elem nodes
5699 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5700 // while ( itN->more() ) {
5702 // // check if a node has been already transformed
5703 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5704 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5705 // nodeMap.insert( make_pair ( node, node ));
5706 // if ( !n2n_isnew.second )
5709 // //double coord[3];
5710 // //coord[0] = node->X();
5711 // //coord[1] = node->Y();
5712 // //coord[2] = node->Z();
5713 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5714 // double dx = (node->X() - thePoint.X()) * scaleX;
5715 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5716 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5717 // if ( theTargetMesh ) {
5718 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5719 // const SMDS_MeshNode * newNode =
5720 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5721 // n2n_isnew.first->second = newNode;
5722 // myLastCreatedNodes.Append(newNode);
5723 // srcNodes.Append( node );
5725 // else if ( theCopy ) {
5726 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5727 // const SMDS_MeshNode * newNode =
5728 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5729 // n2n_isnew.first->second = newNode;
5730 // myLastCreatedNodes.Append(newNode);
5731 // srcNodes.Append( node );
5734 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5735 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5736 // // node position on shape becomes invalid
5737 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5738 // ( SMDS_SpacePosition::originSpacePosition() );
5741 // // keep inverse elements
5742 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5743 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5744 // // while ( invElemIt->more() ) {
5745 // // const SMDS_MeshElement* iel = invElemIt->next();
5746 // // inverseElemSet.insert( iel );
5752 // // either create new elements or reverse mirrored ones
5753 // //if ( !theCopy && !needReverse && !theTargetMesh )
5754 // if ( !theCopy && !theTargetMesh )
5755 // return PGroupIDs();
5757 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5758 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5759 // theElems.insert( *invElemIt );
5761 // // replicate or reverse elements
5764 // REV_TETRA = 0, // = nbNodes - 4
5765 // REV_PYRAMID = 1, // = nbNodes - 4
5766 // REV_PENTA = 2, // = nbNodes - 4
5768 // REV_HEXA = 4, // = nbNodes - 4
5771 // int index[][8] = {
5772 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5773 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5774 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5775 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5776 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5777 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5780 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5782 // const SMDS_MeshElement* elem = *itElem;
5783 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5786 // int nbNodes = elem->NbNodes();
5787 // int elemType = elem->GetType();
5789 // if (elem->IsPoly()) {
5790 // // Polygon or Polyhedral Volume
5791 // switch ( elemType ) {
5792 // case SMDSAbs_Face:
5794 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5796 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5797 // while (itN->more()) {
5798 // const SMDS_MeshNode* node =
5799 // static_cast<const SMDS_MeshNode*>(itN->next());
5800 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5801 // if (nodeMapIt == nodeMap.end())
5802 // break; // not all nodes transformed
5803 // //if (needReverse) {
5804 // // // reverse mirrored faces and volumes
5805 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5807 // poly_nodes[iNode] = (*nodeMapIt).second;
5811 // if ( iNode != nbNodes )
5812 // continue; // not all nodes transformed
5814 // if ( theTargetMesh ) {
5815 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5816 // srcElems.Append( elem );
5818 // else if ( theCopy ) {
5819 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5820 // srcElems.Append( elem );
5823 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5827 // case SMDSAbs_Volume:
5829 // // ATTENTION: Reversing is not yet done!!!
5830 // const SMDS_VtkVolume* aPolyedre =
5831 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5832 // if (!aPolyedre) {
5833 // MESSAGE("Warning: bad volumic element");
5837 // vector<const SMDS_MeshNode*> poly_nodes;
5838 // vector<int> quantities;
5840 // bool allTransformed = true;
5841 // int nbFaces = aPolyedre->NbFaces();
5842 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5843 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5844 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5845 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5846 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5847 // if (nodeMapIt == nodeMap.end()) {
5848 // allTransformed = false; // not all nodes transformed
5850 // poly_nodes.push_back((*nodeMapIt).second);
5853 // quantities.push_back(nbFaceNodes);
5855 // if ( !allTransformed )
5856 // continue; // not all nodes transformed
5858 // if ( theTargetMesh ) {
5859 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5860 // srcElems.Append( elem );
5862 // else if ( theCopy ) {
5863 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5864 // srcElems.Append( elem );
5867 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5876 // // Regular elements
5877 // int* i = index[ FORWARD ];
5878 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5879 // // if ( elemType == SMDSAbs_Face )
5880 // // i = index[ REV_FACE ];
5882 // // i = index[ nbNodes - 4 ];
5884 // if(elem->IsQuadratic()) {
5885 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5887 // //if(needReverse) {
5888 // // if(nbNodes==3) { // quadratic edge
5889 // // static int anIds[] = {1,0,2};
5892 // // else if(nbNodes==6) { // quadratic triangle
5893 // // static int anIds[] = {0,2,1,5,4,3};
5896 // // else if(nbNodes==8) { // quadratic quadrangle
5897 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5900 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5901 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5904 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5905 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5908 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5909 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5912 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5913 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5919 // // find transformed nodes
5920 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5922 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5923 // while ( itN->more() ) {
5924 // const SMDS_MeshNode* node =
5925 // static_cast<const SMDS_MeshNode*>( itN->next() );
5926 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5927 // if ( nodeMapIt == nodeMap.end() )
5928 // break; // not all nodes transformed
5929 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5931 // if ( iNode != nbNodes )
5932 // continue; // not all nodes transformed
5934 // if ( theTargetMesh ) {
5935 // if ( SMDS_MeshElement* copy =
5936 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5937 // myLastCreatedElems.Append( copy );
5938 // srcElems.Append( elem );
5941 // else if ( theCopy ) {
5942 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5943 // myLastCreatedElems.Append( copy );
5944 // srcElems.Append( elem );
5948 // // reverse element as it was reversed by transformation
5949 // if ( nbNodes > 2 )
5950 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5954 // PGroupIDs newGroupIDs;
5956 // if ( theMakeGroups && theCopy ||
5957 // theMakeGroups && theTargetMesh ) {
5958 // string groupPostfix = "scaled";
5959 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5962 // return newGroupIDs;
5966 //=======================================================================
5968 * \brief Create groups of elements made during transformation
5969 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5970 * \param elemGens - elements making corresponding myLastCreatedElems
5971 * \param postfix - to append to names of new groups
5973 //=======================================================================
5975 SMESH_MeshEditor::PGroupIDs
5976 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5977 const SMESH_SequenceOfElemPtr& elemGens,
5978 const std::string& postfix,
5979 SMESH_Mesh* targetMesh)
5981 PGroupIDs newGroupIDs( new list<int> );
5982 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5984 // Sort existing groups by types and collect their names
5986 // to store an old group and a generated new one
5987 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5988 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5990 set< string > groupNames;
5992 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5993 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5994 while ( groupIt->more() ) {
5995 SMESH_Group * group = groupIt->next();
5996 if ( !group ) continue;
5997 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5998 if ( !groupDS || groupDS->IsEmpty() ) continue;
5999 groupNames.insert( group->GetName() );
6000 groupDS->SetStoreName( group->GetName() );
6001 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6006 // loop on nodes and elements
6007 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6009 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6010 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6011 if ( gens.Length() != elems.Length() )
6012 throw SALOME_Exception(LOCALIZED("invalid args"));
6014 // loop on created elements
6015 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6017 const SMDS_MeshElement* sourceElem = gens( iElem );
6018 if ( !sourceElem ) {
6019 MESSAGE("generateGroups(): NULL source element");
6022 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6023 if ( groupsOldNew.empty() ) {
6024 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6025 ++iElem; // skip all elements made by sourceElem
6028 // collect all elements made by sourceElem
6029 list< const SMDS_MeshElement* > resultElems;
6030 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6031 if ( resElem != sourceElem )
6032 resultElems.push_back( resElem );
6033 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6034 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6035 if ( resElem != sourceElem )
6036 resultElems.push_back( resElem );
6037 // do not generate element groups from node ones
6038 if ( sourceElem->GetType() == SMDSAbs_Node &&
6039 elems( iElem )->GetType() != SMDSAbs_Node )
6042 // add resultElems to groups made by ones the sourceElem belongs to
6043 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6044 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6046 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6047 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6049 SMDS_MeshGroup* & newGroup = gOldNew->second;
6050 if ( !newGroup )// create a new group
6053 string name = oldGroup->GetStoreName();
6054 if ( !targetMesh ) {
6058 while ( !groupNames.insert( name ).second ) // name exists
6064 TCollection_AsciiString nbStr(nb+1);
6065 name.resize( name.rfind('_')+1 );
6066 name += nbStr.ToCString();
6073 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6075 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6076 newGroup = & groupDS->SMDSGroup();
6077 newGroupIDs->push_back( id );
6080 // fill in a new group
6081 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6082 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6083 newGroup->Add( *resElemIt );
6086 } // loop on created elements
6087 }// loop on nodes and elements
6092 //================================================================================
6094 * \brief Return list of group of nodes close to each other within theTolerance
6095 * Search among theNodes or in the whole mesh if theNodes is empty using
6096 * an Octree algorithm
6098 //================================================================================
6100 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6101 const double theTolerance,
6102 TListOfListOfNodes & theGroupsOfNodes)
6104 myLastCreatedElems.Clear();
6105 myLastCreatedNodes.Clear();
6107 if ( theNodes.empty() )
6108 { // get all nodes in the mesh
6109 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6110 while ( nIt->more() )
6111 theNodes.insert( theNodes.end(),nIt->next());
6114 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6118 //=======================================================================
6120 * \brief Implementation of search for the node closest to point
6122 //=======================================================================
6124 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6126 //---------------------------------------------------------------------
6128 * \brief Constructor
6130 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6132 myMesh = ( SMESHDS_Mesh* ) theMesh;
6134 TIDSortedNodeSet nodes;
6136 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6137 while ( nIt->more() )
6138 nodes.insert( nodes.end(), nIt->next() );
6140 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6142 // get max size of a leaf box
6143 SMESH_OctreeNode* tree = myOctreeNode;
6144 while ( !tree->isLeaf() )
6146 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6150 myHalfLeafSize = tree->maxSize() / 2.;
6153 //---------------------------------------------------------------------
6155 * \brief Move node and update myOctreeNode accordingly
6157 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6159 myOctreeNode->UpdateByMoveNode( node, toPnt );
6160 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6163 //---------------------------------------------------------------------
6165 * \brief Do it's job
6167 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6169 map<double, const SMDS_MeshNode*> dist2Nodes;
6170 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6171 if ( !dist2Nodes.empty() )
6172 return dist2Nodes.begin()->second;
6173 list<const SMDS_MeshNode*> nodes;
6174 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6176 double minSqDist = DBL_MAX;
6177 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6179 // sort leafs by their distance from thePnt
6180 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6181 TDistTreeMap treeMap;
6182 list< SMESH_OctreeNode* > treeList;
6183 list< SMESH_OctreeNode* >::iterator trIt;
6184 treeList.push_back( myOctreeNode );
6186 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6187 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6188 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6190 SMESH_OctreeNode* tree = *trIt;
6191 if ( !tree->isLeaf() ) // put children to the queue
6193 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6194 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6195 while ( cIt->more() )
6196 treeList.push_back( cIt->next() );
6198 else if ( tree->NbNodes() ) // put a tree to the treeMap
6200 const Bnd_B3d& box = tree->getBox();
6201 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6202 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6203 if ( !it_in.second ) // not unique distance to box center
6204 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6207 // find distance after which there is no sense to check tree's
6208 double sqLimit = DBL_MAX;
6209 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6210 if ( treeMap.size() > 5 ) {
6211 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6212 const Bnd_B3d& box = closestTree->getBox();
6213 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6214 sqLimit = limit * limit;
6216 // get all nodes from trees
6217 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6218 if ( sqDist_tree->first > sqLimit )
6220 SMESH_OctreeNode* tree = sqDist_tree->second;
6221 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6224 // find closest among nodes
6225 minSqDist = DBL_MAX;
6226 const SMDS_MeshNode* closestNode = 0;
6227 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6228 for ( ; nIt != nodes.end(); ++nIt ) {
6229 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6230 if ( minSqDist > sqDist ) {
6238 //---------------------------------------------------------------------
6242 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6244 //---------------------------------------------------------------------
6246 * \brief Return the node tree
6248 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6251 SMESH_OctreeNode* myOctreeNode;
6252 SMESHDS_Mesh* myMesh;
6253 double myHalfLeafSize; // max size of a leaf box
6256 //=======================================================================
6258 * \brief Return SMESH_NodeSearcher
6260 //=======================================================================
6262 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6264 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6267 // ========================================================================
6268 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6270 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6271 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6272 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6274 //=======================================================================
6276 * \brief Octal tree of bounding boxes of elements
6278 //=======================================================================
6280 class ElementBndBoxTree : public SMESH_Octree
6284 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
6285 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6286 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6287 ~ElementBndBoxTree();
6290 ElementBndBoxTree() {}
6291 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6292 void buildChildrenData();
6293 Bnd_B3d* buildRootBox();
6295 //!< Bounding box of element
6296 struct ElementBox : public Bnd_B3d
6298 const SMDS_MeshElement* _element;
6299 int _refCount; // an ElementBox can be included in several tree branches
6300 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6302 vector< ElementBox* > _elements;
6305 //================================================================================
6307 * \brief ElementBndBoxTree creation
6309 //================================================================================
6311 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
6312 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6314 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6315 _elements.reserve( nbElems );
6317 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6318 while ( elemIt->more() )
6319 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6321 if ( _elements.size() > MaxNbElemsInLeaf )
6327 //================================================================================
6331 //================================================================================
6333 ElementBndBoxTree::~ElementBndBoxTree()
6335 for ( int i = 0; i < _elements.size(); ++i )
6336 if ( --_elements[i]->_refCount <= 0 )
6337 delete _elements[i];
6340 //================================================================================
6342 * \brief Return the maximal box
6344 //================================================================================
6346 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6348 Bnd_B3d* box = new Bnd_B3d;
6349 for ( int i = 0; i < _elements.size(); ++i )
6350 box->Add( *_elements[i] );
6354 //================================================================================
6356 * \brief Redistrubute element boxes among children
6358 //================================================================================
6360 void ElementBndBoxTree::buildChildrenData()
6362 for ( int i = 0; i < _elements.size(); ++i )
6364 for (int j = 0; j < 8; j++)
6366 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6368 _elements[i]->_refCount++;
6369 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6372 _elements[i]->_refCount--;
6376 for (int j = 0; j < 8; j++)
6378 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6379 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6380 child->myIsLeaf = true;
6382 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6383 child->_elements.resize( child->_elements.size() ); // compact
6387 //================================================================================
6389 * \brief Return elements which can include the point
6391 //================================================================================
6393 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6394 TIDSortedElemSet& foundElems)
6396 if ( level() && getBox().IsOut( point.XYZ() ))
6401 for ( int i = 0; i < _elements.size(); ++i )
6402 if ( !_elements[i]->IsOut( point.XYZ() ))
6403 foundElems.insert( _elements[i]->_element );
6407 for (int i = 0; i < 8; i++)
6408 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6412 //================================================================================
6414 * \brief Return elements which can be intersected by the line
6416 //================================================================================
6418 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6419 TIDSortedElemSet& foundElems)
6421 if ( level() && getBox().IsOut( line ))
6426 for ( int i = 0; i < _elements.size(); ++i )
6427 if ( !_elements[i]->IsOut( line ))
6428 foundElems.insert( _elements[i]->_element );
6432 for (int i = 0; i < 8; i++)
6433 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6437 //================================================================================
6439 * \brief Construct the element box
6441 //================================================================================
6443 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6447 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6448 while ( nIt->more() )
6449 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6450 Enlarge( tolerance );
6455 //=======================================================================
6457 * \brief Implementation of search for the elements by point and
6458 * of classification of point in 2D mesh
6460 //=======================================================================
6462 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6464 SMESHDS_Mesh* _mesh;
6465 ElementBndBoxTree* _ebbTree;
6466 SMESH_NodeSearcherImpl* _nodeSearcher;
6467 SMDSAbs_ElementType _elementType;
6469 bool _outerFacesFound;
6470 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6472 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6473 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6474 ~SMESH_ElementSearcherImpl()
6476 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6477 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6479 virtual int FindElementsByPoint(const gp_Pnt& point,
6480 SMDSAbs_ElementType type,
6481 vector< const SMDS_MeshElement* >& foundElements);
6482 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6484 void GetElementsNearLine( const gp_Ax1& line,
6485 SMDSAbs_ElementType type,
6486 vector< const SMDS_MeshElement* >& foundElems);
6487 double getTolerance();
6488 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6489 const double tolerance, double & param);
6490 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6491 bool isOuterBoundary(const SMDS_MeshElement* face) const
6493 return _outerFaces.empty() || _outerFaces.count(face);
6495 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6497 const SMDS_MeshElement* _face;
6499 bool _coincides; //!< the line lays in face plane
6500 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6501 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6503 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6506 TIDSortedElemSet _faces;
6507 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6508 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6512 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6514 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6515 << ", _coincides="<<i._coincides << ")";
6518 //=======================================================================
6520 * \brief define tolerance for search
6522 //=======================================================================
6524 double SMESH_ElementSearcherImpl::getTolerance()
6526 if ( _tolerance < 0 )
6528 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6531 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6533 double boxSize = _nodeSearcher->getTree()->maxSize();
6534 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6536 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6538 double boxSize = _ebbTree->maxSize();
6539 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6541 if ( _tolerance == 0 )
6543 // define tolerance by size of a most complex element
6544 int complexType = SMDSAbs_Volume;
6545 while ( complexType > SMDSAbs_All &&
6546 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6548 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6550 if ( complexType == int( SMDSAbs_Node ))
6552 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6554 if ( meshInfo.NbNodes() > 2 )
6555 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6559 SMDS_ElemIteratorPtr elemIt =
6560 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6561 const SMDS_MeshElement* elem = elemIt->next();
6562 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6563 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6564 while ( nodeIt->more() )
6566 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6567 elemSize = max( dist, elemSize );
6570 _tolerance = 1e-4 * elemSize;
6576 //================================================================================
6578 * \brief Find intersection of the line and an edge of face and return parameter on line
6580 //================================================================================
6582 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6583 const SMDS_MeshElement* face,
6590 GeomAPI_ExtremaCurveCurve anExtCC;
6591 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6593 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6594 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6596 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6597 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6598 anExtCC.Init( lineCurve, edge);
6599 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6601 Quantity_Parameter pl, pe;
6602 anExtCC.LowerDistanceParameters( pl, pe );
6604 if ( ++nbInts == 2 )
6608 if ( nbInts > 0 ) param /= nbInts;
6611 //================================================================================
6613 * \brief Find all faces belonging to the outer boundary of mesh
6615 //================================================================================
6617 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6619 if ( _outerFacesFound ) return;
6621 // Collect all outer faces by passing from one outer face to another via their links
6622 // and BTW find out if there are internal faces at all.
6624 // checked links and links where outer boundary meets internal one
6625 set< SMESH_TLink > visitedLinks, seamLinks;
6627 // links to treat with already visited faces sharing them
6628 list < TFaceLink > startLinks;
6630 // load startLinks with the first outerFace
6631 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6632 _outerFaces.insert( outerFace );
6634 TIDSortedElemSet emptySet;
6635 while ( !startLinks.empty() )
6637 const SMESH_TLink& link = startLinks.front()._link;
6638 TIDSortedElemSet& faces = startLinks.front()._faces;
6640 outerFace = *faces.begin();
6641 // find other faces sharing the link
6642 const SMDS_MeshElement* f;
6643 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6646 // select another outer face among the found
6647 const SMDS_MeshElement* outerFace2 = 0;
6648 if ( faces.size() == 2 )
6650 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6652 else if ( faces.size() > 2 )
6654 seamLinks.insert( link );
6656 // link direction within the outerFace
6657 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6658 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6659 int i1 = outerFace->GetNodeIndex( link.node1() );
6660 int i2 = outerFace->GetNodeIndex( link.node2() );
6661 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6662 if ( rev ) n1n2.Reverse();
6664 gp_XYZ ofNorm, fNorm;
6665 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6667 // direction from the link inside outerFace
6668 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6669 // sort all other faces by angle with the dirInOF
6670 map< double, const SMDS_MeshElement* > angle2Face;
6671 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6672 for ( ; face != faces.end(); ++face )
6674 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6676 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6677 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6678 if ( angle < 0 ) angle += 2*PI;
6679 angle2Face.insert( make_pair( angle, *face ));
6681 if ( !angle2Face.empty() )
6682 outerFace2 = angle2Face.begin()->second;
6685 // store the found outer face and add its links to continue seaching from
6688 _outerFaces.insert( outerFace );
6689 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6690 for ( int i = 0; i < nbNodes; ++i )
6692 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6693 if ( visitedLinks.insert( link2 ).second )
6694 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6697 startLinks.pop_front();
6699 _outerFacesFound = true;
6701 if ( !seamLinks.empty() )
6703 // There are internal boundaries touching the outher one,
6704 // find all faces of internal boundaries in order to find
6705 // faces of boundaries of holes, if any.
6710 _outerFaces.clear();
6714 //=======================================================================
6716 * \brief Find elements of given type where the given point is IN or ON.
6717 * Returns nb of found elements and elements them-selves.
6719 * 'ALL' type means elements of any type excluding nodes and 0D elements
6721 //=======================================================================
6723 int SMESH_ElementSearcherImpl::
6724 FindElementsByPoint(const gp_Pnt& point,
6725 SMDSAbs_ElementType type,
6726 vector< const SMDS_MeshElement* >& foundElements)
6728 foundElements.clear();
6730 double tolerance = getTolerance();
6732 // =================================================================================
6733 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6735 if ( !_nodeSearcher )
6736 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6738 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6739 if ( !closeNode ) return foundElements.size();
6741 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6742 return foundElements.size(); // to far from any node
6744 if ( type == SMDSAbs_Node )
6746 foundElements.push_back( closeNode );
6750 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6751 while ( elemIt->more() )
6752 foundElements.push_back( elemIt->next() );
6755 // =================================================================================
6756 else // elements more complex than 0D
6758 if ( !_ebbTree || _elementType != type )
6760 if ( _ebbTree ) delete _ebbTree;
6761 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6763 TIDSortedElemSet suspectElems;
6764 _ebbTree->getElementsNearPoint( point, suspectElems );
6765 TIDSortedElemSet::iterator elem = suspectElems.begin();
6766 for ( ; elem != suspectElems.end(); ++elem )
6767 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6768 foundElements.push_back( *elem );
6770 return foundElements.size();
6773 //================================================================================
6775 * \brief Classify the given point in the closed 2D mesh
6777 //================================================================================
6779 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6781 double tolerance = getTolerance();
6782 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6784 if ( _ebbTree ) delete _ebbTree;
6785 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6787 // Algo: analyse transition of a line starting at the point through mesh boundary;
6788 // try three lines parallel to axis of the coordinate system and perform rough
6789 // analysis. If solution is not clear perform thorough analysis.
6791 const int nbAxes = 3;
6792 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6793 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6794 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6795 multimap< int, int > nbInt2Axis; // to find the simplest case
6796 for ( int axis = 0; axis < nbAxes; ++axis )
6798 gp_Ax1 lineAxis( point, axisDir[axis]);
6799 gp_Lin line ( lineAxis );
6801 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6802 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6804 // Intersect faces with the line
6806 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6807 TIDSortedElemSet::iterator face = suspectFaces.begin();
6808 for ( ; face != suspectFaces.end(); ++face )
6812 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6813 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6815 // perform intersection
6816 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6817 if ( !intersection.IsDone() )
6819 if ( intersection.IsInQuadric() )
6821 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6823 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6825 gp_Pnt intersectionPoint = intersection.Point(1);
6826 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6827 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6830 // Analyse intersections roughly
6832 int nbInter = u2inters.size();
6836 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6837 if ( nbInter == 1 ) // not closed mesh
6838 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6840 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6843 if ( (f<0) == (l<0) )
6846 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6847 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6848 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6851 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6853 if ( _outerFacesFound ) break; // pass to thorough analysis
6855 } // three attempts - loop on CS axes
6857 // Analyse intersections thoroughly.
6858 // We make two loops maximum, on the first one we only exclude touching intersections,
6859 // on the second, if situation is still unclear, we gather and use information on
6860 // position of faces (internal or outer). If faces position is already gathered,
6861 // we make the second loop right away.
6863 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6865 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6866 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6868 int axis = nb_axis->second;
6869 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6871 gp_Ax1 lineAxis( point, axisDir[axis]);
6872 gp_Lin line ( lineAxis );
6874 // add tangent intersections to u2inters
6876 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6877 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6878 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6879 u2inters.insert(make_pair( param, *tgtInt ));
6880 tangentInters[ axis ].clear();
6882 // Count intersections before and after the point excluding touching ones.
6883 // If hasPositionInfo we count intersections of outer boundary only
6885 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6886 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6887 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6888 bool ok = ! u_int1->second._coincides;
6889 while ( ok && u_int1 != u2inters.end() )
6891 double u = u_int1->first;
6892 bool touchingInt = false;
6893 if ( ++u_int2 != u2inters.end() )
6895 // skip intersections at the same point (if the line passes through edge or node)
6897 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6903 // skip tangent intersections
6905 const SMDS_MeshElement* prevFace = u_int1->second._face;
6906 while ( ok && u_int2->second._coincides )
6908 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6914 ok = ( u_int2 != u2inters.end() );
6919 // skip intersections at the same point after tangent intersections
6922 double u2 = u_int2->first;
6924 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6930 // decide if we skipped a touching intersection
6931 if ( nbSamePnt + nbTgt > 0 )
6933 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6934 map< double, TInters >::iterator u_int = u_int1;
6935 for ( ; u_int != u_int2; ++u_int )
6937 if ( u_int->second._coincides ) continue;
6938 double dot = u_int->second._faceNorm * line.Direction();
6939 if ( dot > maxDot ) maxDot = dot;
6940 if ( dot < minDot ) minDot = dot;
6942 touchingInt = ( minDot*maxDot < 0 );
6947 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6958 u_int1 = u_int2; // to next intersection
6960 } // loop on intersections with one line
6964 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6967 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6970 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6971 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6973 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6976 if ( (f<0) == (l<0) )
6979 if ( hasPositionInfo )
6980 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6982 } // loop on intersections of the tree lines - thorough analysis
6984 if ( !hasPositionInfo )
6986 // gather info on faces position - is face in the outer boundary or not
6987 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6988 findOuterBoundary( u2inters.begin()->second._face );
6991 } // two attempts - with and w/o faces position info in the mesh
6993 return TopAbs_UNKNOWN;
6996 //=======================================================================
6998 * \brief Return elements possibly intersecting the line
7000 //=======================================================================
7002 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7003 SMDSAbs_ElementType type,
7004 vector< const SMDS_MeshElement* >& foundElems)
7006 if ( !_ebbTree || _elementType != type )
7008 if ( _ebbTree ) delete _ebbTree;
7009 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
7011 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7012 _ebbTree->getElementsNearLine( line, suspectFaces );
7013 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7016 //=======================================================================
7018 * \brief Return SMESH_ElementSearcher
7020 //=======================================================================
7022 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7024 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7027 //=======================================================================
7029 * \brief Return true if the point is IN or ON of the element
7031 //=======================================================================
7033 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7035 if ( element->GetType() == SMDSAbs_Volume)
7037 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7040 // get ordered nodes
7042 vector< gp_XYZ > xyz;
7043 vector<const SMDS_MeshNode*> nodeList;
7045 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7046 if ( element->IsQuadratic() ) {
7047 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7048 nodeIt = f->interlacedNodesElemIterator();
7049 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7050 nodeIt = e->interlacedNodesElemIterator();
7052 while ( nodeIt->more() )
7054 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7055 xyz.push_back( TNodeXYZ(node) );
7056 nodeList.push_back(node);
7059 int i, nbNodes = element->NbNodes();
7061 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7063 // compute face normal
7064 gp_Vec faceNorm(0,0,0);
7065 xyz.push_back( xyz.front() );
7066 nodeList.push_back( nodeList.front() );
7067 for ( i = 0; i < nbNodes; ++i )
7069 gp_Vec edge1( xyz[i+1], xyz[i]);
7070 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7071 faceNorm += edge1 ^ edge2;
7073 double normSize = faceNorm.Magnitude();
7074 if ( normSize <= tol )
7076 // degenerated face: point is out if it is out of all face edges
7077 for ( i = 0; i < nbNodes; ++i )
7079 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7080 if ( !isOut( &edge, point, tol ))
7085 faceNorm /= normSize;
7087 // check if the point lays on face plane
7088 gp_Vec n2p( xyz[0], point );
7089 if ( fabs( n2p * faceNorm ) > tol )
7090 return true; // not on face plane
7092 // check if point is out of face boundary:
7093 // define it by closest transition of a ray point->infinity through face boundary
7094 // on the face plane.
7095 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7096 // to find intersections of the ray with the boundary.
7098 gp_Vec plnNorm = ray ^ faceNorm;
7099 normSize = plnNorm.Magnitude();
7100 if ( normSize <= tol ) return false; // point coincides with the first node
7101 plnNorm /= normSize;
7102 // for each node of the face, compute its signed distance to the plane
7103 vector<double> dist( nbNodes + 1);
7104 for ( i = 0; i < nbNodes; ++i )
7106 gp_Vec n2p( xyz[i], point );
7107 dist[i] = n2p * plnNorm;
7109 dist.back() = dist.front();
7110 // find the closest intersection
7112 double rClosest, distClosest = 1e100;;
7114 for ( i = 0; i < nbNodes; ++i )
7117 if ( fabs( dist[i]) < tol )
7119 else if ( fabs( dist[i+1]) < tol )
7121 else if ( dist[i] * dist[i+1] < 0 )
7122 r = dist[i] / ( dist[i] - dist[i+1] );
7124 continue; // no intersection
7125 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7126 gp_Vec p2int ( point, pInt);
7127 if ( p2int * ray > -tol ) // right half-space
7129 double intDist = p2int.SquareMagnitude();
7130 if ( intDist < distClosest )
7135 distClosest = intDist;
7140 return true; // no intesections - out
7142 // analyse transition
7143 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7144 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7145 gp_Vec p2int ( point, pClosest );
7146 bool out = (edgeNorm * p2int) < -tol;
7147 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7150 // ray pass through a face node; analyze transition through an adjacent edge
7151 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7152 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7153 gp_Vec edgeAdjacent( p1, p2 );
7154 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7155 bool out2 = (edgeNorm2 * p2int) < -tol;
7157 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7158 return covexCorner ? (out || out2) : (out && out2);
7160 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7162 // point is out of edge if it is NOT ON any straight part of edge
7163 // (we consider quadratic edge as being composed of two straight parts)
7164 for ( i = 1; i < nbNodes; ++i )
7166 gp_Vec edge( xyz[i-1], xyz[i]);
7167 gp_Vec n1p ( xyz[i-1], point);
7168 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7171 gp_Vec n2p( xyz[i], point );
7172 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7174 return false; // point is ON this part
7178 // Node or 0D element -------------------------------------------------------------------------
7180 gp_Vec n2p ( xyz[0], point );
7181 return n2p.Magnitude() <= tol;
7186 //=======================================================================
7187 //function : SimplifyFace
7189 //=======================================================================
7190 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7191 vector<const SMDS_MeshNode *>& poly_nodes,
7192 vector<int>& quantities) const
7194 int nbNodes = faceNodes.size();
7199 set<const SMDS_MeshNode*> nodeSet;
7201 // get simple seq of nodes
7202 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7203 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7204 int iSimple = 0, nbUnique = 0;
7206 simpleNodes[iSimple++] = faceNodes[0];
7208 for (int iCur = 1; iCur < nbNodes; iCur++) {
7209 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7210 simpleNodes[iSimple++] = faceNodes[iCur];
7211 if (nodeSet.insert( faceNodes[iCur] ).second)
7215 int nbSimple = iSimple;
7216 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7226 bool foundLoop = (nbSimple > nbUnique);
7229 set<const SMDS_MeshNode*> loopSet;
7230 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7231 const SMDS_MeshNode* n = simpleNodes[iSimple];
7232 if (!loopSet.insert( n ).second) {
7236 int iC = 0, curLast = iSimple;
7237 for (; iC < curLast; iC++) {
7238 if (simpleNodes[iC] == n) break;
7240 int loopLen = curLast - iC;
7242 // create sub-element
7244 quantities.push_back(loopLen);
7245 for (; iC < curLast; iC++) {
7246 poly_nodes.push_back(simpleNodes[iC]);
7249 // shift the rest nodes (place from the first loop position)
7250 for (iC = curLast + 1; iC < nbSimple; iC++) {
7251 simpleNodes[iC - loopLen] = simpleNodes[iC];
7253 nbSimple -= loopLen;
7256 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7257 } // while (foundLoop)
7261 quantities.push_back(iSimple);
7262 for (int i = 0; i < iSimple; i++)
7263 poly_nodes.push_back(simpleNodes[i]);
7269 //=======================================================================
7270 //function : MergeNodes
7271 //purpose : In each group, the cdr of nodes are substituted by the first one
7273 //=======================================================================
7275 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7277 MESSAGE("MergeNodes");
7278 myLastCreatedElems.Clear();
7279 myLastCreatedNodes.Clear();
7281 SMESHDS_Mesh* aMesh = GetMeshDS();
7283 TNodeNodeMap nodeNodeMap; // node to replace - new node
7284 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7285 list< int > rmElemIds, rmNodeIds;
7287 // Fill nodeNodeMap and elems
7289 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7290 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7291 list<const SMDS_MeshNode*>& nodes = *grIt;
7292 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7293 const SMDS_MeshNode* nToKeep = *nIt;
7294 //MESSAGE("node to keep " << nToKeep->GetID());
7295 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7296 const SMDS_MeshNode* nToRemove = *nIt;
7297 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7298 if ( nToRemove != nToKeep ) {
7299 //MESSAGE(" node to remove " << nToRemove->GetID());
7300 rmNodeIds.push_back( nToRemove->GetID() );
7301 AddToSameGroups( nToKeep, nToRemove, aMesh );
7304 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7305 while ( invElemIt->more() ) {
7306 const SMDS_MeshElement* elem = invElemIt->next();
7311 // Change element nodes or remove an element
7313 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7314 for ( ; eIt != elems.end(); eIt++ ) {
7315 const SMDS_MeshElement* elem = *eIt;
7316 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7317 int nbNodes = elem->NbNodes();
7318 int aShapeId = FindShape( elem );
7320 set<const SMDS_MeshNode*> nodeSet;
7321 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7322 int iUnique = 0, iCur = 0, nbRepl = 0;
7323 vector<int> iRepl( nbNodes );
7325 // get new seq of nodes
7326 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7327 while ( itN->more() ) {
7328 const SMDS_MeshNode* n =
7329 static_cast<const SMDS_MeshNode*>( itN->next() );
7331 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7332 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7334 // BUG 0020185: begin
7336 bool stopRecur = false;
7337 set<const SMDS_MeshNode*> nodesRecur;
7338 nodesRecur.insert(n);
7339 while (!stopRecur) {
7340 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7341 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7342 n = (*nnIt_i).second;
7343 if (!nodesRecur.insert(n).second) {
7344 // error: recursive dependancy
7353 iRepl[ nbRepl++ ] = iCur;
7355 curNodes[ iCur ] = n;
7356 bool isUnique = nodeSet.insert( n ).second;
7358 uniqueNodes[ iUnique++ ] = n;
7362 // Analyse element topology after replacement
7365 int nbUniqueNodes = nodeSet.size();
7366 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7367 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7368 // Polygons and Polyhedral volumes
7369 if (elem->IsPoly()) {
7371 if (elem->GetType() == SMDSAbs_Face) {
7373 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7375 for (; inode < nbNodes; inode++) {
7376 face_nodes[inode] = curNodes[inode];
7379 vector<const SMDS_MeshNode *> polygons_nodes;
7380 vector<int> quantities;
7381 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7385 for (int iface = 0; iface < nbNew - 1; iface++) {
7386 int nbNodes = quantities[iface];
7387 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7388 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7389 poly_nodes[ii] = polygons_nodes[inode];
7391 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7392 myLastCreatedElems.Append(newElem);
7394 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7397 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7398 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7399 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7401 if (nbNew > 0) quid = nbNew - 1;
7402 vector<int> newquant(quantities.begin()+quid, quantities.end());
7403 const SMDS_MeshElement* newElem = 0;
7404 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7405 myLastCreatedElems.Append(newElem);
7406 if ( aShapeId && newElem )
7407 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7408 rmElemIds.push_back(elem->GetID());
7411 rmElemIds.push_back(elem->GetID());
7415 else if (elem->GetType() == SMDSAbs_Volume) {
7416 // Polyhedral volume
7417 if (nbUniqueNodes < 4) {
7418 rmElemIds.push_back(elem->GetID());
7421 // each face has to be analyzed in order to check volume validity
7422 const SMDS_VtkVolume* aPolyedre =
7423 dynamic_cast<const SMDS_VtkVolume*>( elem );
7425 int nbFaces = aPolyedre->NbFaces();
7427 vector<const SMDS_MeshNode *> poly_nodes;
7428 vector<int> quantities;
7430 for (int iface = 1; iface <= nbFaces; iface++) {
7431 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7432 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7434 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7435 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7436 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7437 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7438 faceNode = (*nnIt).second;
7440 faceNodes[inode - 1] = faceNode;
7443 SimplifyFace(faceNodes, poly_nodes, quantities);
7446 if (quantities.size() > 3) {
7447 // to be done: remove coincident faces
7450 if (quantities.size() > 3)
7452 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7453 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7454 const SMDS_MeshElement* newElem = 0;
7455 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7456 myLastCreatedElems.Append(newElem);
7457 if ( aShapeId && newElem )
7458 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7459 rmElemIds.push_back(elem->GetID());
7463 rmElemIds.push_back(elem->GetID());
7474 // TODO not all the possible cases are solved. Find something more generic?
7475 switch ( nbNodes ) {
7476 case 2: ///////////////////////////////////// EDGE
7477 isOk = false; break;
7478 case 3: ///////////////////////////////////// TRIANGLE
7479 isOk = false; break;
7481 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7483 else { //////////////////////////////////// QUADRANGLE
7484 if ( nbUniqueNodes < 3 )
7486 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7487 isOk = false; // opposite nodes stick
7488 //MESSAGE("isOk " << isOk);
7491 case 6: ///////////////////////////////////// PENTAHEDRON
7492 if ( nbUniqueNodes == 4 ) {
7493 // ---------------------------------> tetrahedron
7495 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7496 // all top nodes stick: reverse a bottom
7497 uniqueNodes[ 0 ] = curNodes [ 1 ];
7498 uniqueNodes[ 1 ] = curNodes [ 0 ];
7500 else if (nbRepl == 3 &&
7501 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7502 // all bottom nodes stick: set a top before
7503 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7504 uniqueNodes[ 0 ] = curNodes [ 3 ];
7505 uniqueNodes[ 1 ] = curNodes [ 4 ];
7506 uniqueNodes[ 2 ] = curNodes [ 5 ];
7508 else if (nbRepl == 4 &&
7509 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7510 // a lateral face turns into a line: reverse a bottom
7511 uniqueNodes[ 0 ] = curNodes [ 1 ];
7512 uniqueNodes[ 1 ] = curNodes [ 0 ];
7517 else if ( nbUniqueNodes == 5 ) {
7518 // PENTAHEDRON --------------------> 2 tetrahedrons
7519 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7520 // a bottom node sticks with a linked top one
7522 SMDS_MeshElement* newElem =
7523 aMesh->AddVolume(curNodes[ 3 ],
7526 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7527 myLastCreatedElems.Append(newElem);
7529 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7530 // 2. : reverse a bottom
7531 uniqueNodes[ 0 ] = curNodes [ 1 ];
7532 uniqueNodes[ 1 ] = curNodes [ 0 ];
7542 if(elem->IsQuadratic()) { // Quadratic quadrangle
7554 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7557 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7559 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7560 uniqueNodes[0] = curNodes[0];
7561 uniqueNodes[1] = curNodes[2];
7562 uniqueNodes[2] = curNodes[3];
7563 uniqueNodes[3] = curNodes[5];
7564 uniqueNodes[4] = curNodes[6];
7565 uniqueNodes[5] = curNodes[7];
7568 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7569 uniqueNodes[0] = curNodes[0];
7570 uniqueNodes[1] = curNodes[1];
7571 uniqueNodes[2] = curNodes[2];
7572 uniqueNodes[3] = curNodes[4];
7573 uniqueNodes[4] = curNodes[5];
7574 uniqueNodes[5] = curNodes[6];
7577 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7578 uniqueNodes[0] = curNodes[1];
7579 uniqueNodes[1] = curNodes[2];
7580 uniqueNodes[2] = curNodes[3];
7581 uniqueNodes[3] = curNodes[5];
7582 uniqueNodes[4] = curNodes[6];
7583 uniqueNodes[5] = curNodes[0];
7586 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7587 uniqueNodes[0] = curNodes[0];
7588 uniqueNodes[1] = curNodes[1];
7589 uniqueNodes[2] = curNodes[3];
7590 uniqueNodes[3] = curNodes[4];
7591 uniqueNodes[4] = curNodes[6];
7592 uniqueNodes[5] = curNodes[7];
7595 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7596 uniqueNodes[0] = curNodes[0];
7597 uniqueNodes[1] = curNodes[2];
7598 uniqueNodes[2] = curNodes[3];
7599 uniqueNodes[3] = curNodes[1];
7600 uniqueNodes[4] = curNodes[6];
7601 uniqueNodes[5] = curNodes[7];
7604 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
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[7];
7613 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7614 uniqueNodes[0] = curNodes[0];
7615 uniqueNodes[1] = curNodes[1];
7616 uniqueNodes[2] = curNodes[3];
7617 uniqueNodes[3] = curNodes[4];
7618 uniqueNodes[4] = curNodes[2];
7619 uniqueNodes[5] = curNodes[7];
7622 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7623 uniqueNodes[0] = curNodes[0];
7624 uniqueNodes[1] = curNodes[1];
7625 uniqueNodes[2] = curNodes[2];
7626 uniqueNodes[3] = curNodes[4];
7627 uniqueNodes[4] = curNodes[5];
7628 uniqueNodes[5] = curNodes[3];
7633 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7636 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7640 //////////////////////////////////// HEXAHEDRON
7642 SMDS_VolumeTool hexa (elem);
7643 hexa.SetExternalNormal();
7644 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7645 //////////////////////// ---> tetrahedron
7646 for ( int iFace = 0; iFace < 6; iFace++ ) {
7647 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7648 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7649 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7650 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7651 // one face turns into a point ...
7652 int iOppFace = hexa.GetOppFaceIndex( iFace );
7653 ind = hexa.GetFaceNodesIndices( iOppFace );
7655 iUnique = 2; // reverse a tetrahedron bottom
7656 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7657 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7659 else if ( iUnique >= 0 )
7660 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7662 if ( nbStick == 1 ) {
7663 // ... and the opposite one - into a triangle.
7665 ind = hexa.GetFaceNodesIndices( iFace );
7666 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7673 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7674 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7675 for ( int iFace = 0; iFace < 6; iFace++ ) {
7676 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7677 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7678 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7679 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7680 // one face turns into a point ...
7681 int iOppFace = hexa.GetOppFaceIndex( iFace );
7682 ind = hexa.GetFaceNodesIndices( iOppFace );
7684 iUnique = 2; // reverse a tetrahedron 1 bottom
7685 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7686 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7688 else if ( iUnique >= 0 )
7689 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7691 if ( nbStick == 0 ) {
7692 // ... and the opposite one is a quadrangle
7694 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7695 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7698 SMDS_MeshElement* newElem =
7699 aMesh->AddVolume(curNodes[ind[ 0 ]],
7702 curNodes[indTop[ 0 ]]);
7703 myLastCreatedElems.Append(newElem);
7705 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7712 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7713 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7714 // find indices of quad and tri faces
7715 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7716 for ( iFace = 0; iFace < 6; iFace++ ) {
7717 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7719 for ( iCur = 0; iCur < 4; iCur++ )
7720 nodeSet.insert( curNodes[ind[ iCur ]] );
7721 nbUniqueNodes = nodeSet.size();
7722 if ( nbUniqueNodes == 3 )
7723 iTriFace[ nbTri++ ] = iFace;
7724 else if ( nbUniqueNodes == 4 )
7725 iQuadFace[ nbQuad++ ] = iFace;
7727 if (nbQuad == 2 && nbTri == 4 &&
7728 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7729 // 2 opposite quadrangles stuck with a diagonal;
7730 // sample groups of merged indices: (0-4)(2-6)
7731 // --------------------------------------------> 2 tetrahedrons
7732 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7733 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7734 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7735 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7736 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7737 // stuck with 0-2 diagonal
7745 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7746 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7747 // stuck with 1-3 diagonal
7759 uniqueNodes[ 0 ] = curNodes [ i0 ];
7760 uniqueNodes[ 1 ] = curNodes [ i1d ];
7761 uniqueNodes[ 2 ] = curNodes [ i3d ];
7762 uniqueNodes[ 3 ] = curNodes [ i0t ];
7765 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7769 myLastCreatedElems.Append(newElem);
7771 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7774 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7775 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7776 // --------------------------------------------> prism
7777 // find 2 opposite triangles
7779 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7780 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7781 // find indices of kept and replaced nodes
7782 // and fill unique nodes of 2 opposite triangles
7783 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7784 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7785 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7786 // fill unique nodes
7789 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7790 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7791 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7793 // iCur of a linked node of the opposite face (make normals co-directed):
7794 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7795 // check that correspondent corners of triangles are linked
7796 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7799 uniqueNodes[ iUnique ] = n;
7800 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7809 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7815 } // switch ( nbNodes )
7817 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7820 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7821 // Change nodes of polyedre
7822 const SMDS_VtkVolume* aPolyedre =
7823 dynamic_cast<const SMDS_VtkVolume*>( elem );
7825 int nbFaces = aPolyedre->NbFaces();
7827 vector<const SMDS_MeshNode *> poly_nodes;
7828 vector<int> quantities (nbFaces);
7830 for (int iface = 1; iface <= nbFaces; iface++) {
7831 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7832 quantities[iface - 1] = nbFaceNodes;
7834 for (inode = 1; inode <= nbFaceNodes; inode++) {
7835 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7837 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7838 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7839 curNode = (*nnIt).second;
7841 poly_nodes.push_back(curNode);
7844 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7848 //int elemId = elem->GetID();
7849 //MESSAGE("Change regular element or polygon " << elemId);
7850 SMDSAbs_ElementType etyp = elem->GetType();
7851 uniqueNodes.resize(nbUniqueNodes);
7852 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, false);
7855 myLastCreatedElems.Append(newElem);
7857 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7859 aMesh->RemoveElement(elem);
7863 // Remove invalid regular element or invalid polygon
7864 //MESSAGE("Remove invalid " << elem->GetID());
7865 rmElemIds.push_back( elem->GetID() );
7868 } // loop on elements
7870 // Remove bad elements, then equal nodes (order important)
7872 Remove( rmElemIds, false );
7873 Remove( rmNodeIds, true );
7878 // ========================================================
7879 // class : SortableElement
7880 // purpose : allow sorting elements basing on their nodes
7881 // ========================================================
7882 class SortableElement : public set <const SMDS_MeshElement*>
7886 SortableElement( const SMDS_MeshElement* theElem )
7889 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7890 while ( nodeIt->more() )
7891 this->insert( nodeIt->next() );
7894 const SMDS_MeshElement* Get() const
7897 void Set(const SMDS_MeshElement* e) const
7902 mutable const SMDS_MeshElement* myElem;
7905 //=======================================================================
7906 //function : FindEqualElements
7907 //purpose : Return list of group of elements built on the same nodes.
7908 // Search among theElements or in the whole mesh if theElements is empty
7909 //=======================================================================
7910 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7911 TListOfListOfElementsID & theGroupsOfElementsID)
7913 myLastCreatedElems.Clear();
7914 myLastCreatedNodes.Clear();
7916 typedef set<const SMDS_MeshElement*> TElemsSet;
7917 typedef map< SortableElement, int > TMapOfNodeSet;
7918 typedef list<int> TGroupOfElems;
7921 if ( theElements.empty() )
7922 { // get all elements in the mesh
7923 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7924 while ( eIt->more() )
7925 elems.insert( elems.end(), eIt->next());
7928 elems = theElements;
7930 vector< TGroupOfElems > arrayOfGroups;
7931 TGroupOfElems groupOfElems;
7932 TMapOfNodeSet mapOfNodeSet;
7934 TElemsSet::iterator elemIt = elems.begin();
7935 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7936 const SMDS_MeshElement* curElem = *elemIt;
7937 SortableElement SE(curElem);
7940 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7941 if( !(pp.second) ) {
7942 TMapOfNodeSet::iterator& itSE = pp.first;
7943 ind = (*itSE).second;
7944 arrayOfGroups[ind].push_back(curElem->GetID());
7947 groupOfElems.clear();
7948 groupOfElems.push_back(curElem->GetID());
7949 arrayOfGroups.push_back(groupOfElems);
7954 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7955 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7956 groupOfElems = *groupIt;
7957 if ( groupOfElems.size() > 1 ) {
7958 groupOfElems.sort();
7959 theGroupsOfElementsID.push_back(groupOfElems);
7964 //=======================================================================
7965 //function : MergeElements
7966 //purpose : In each given group, substitute all elements by the first one.
7967 //=======================================================================
7969 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7971 myLastCreatedElems.Clear();
7972 myLastCreatedNodes.Clear();
7974 typedef list<int> TListOfIDs;
7975 TListOfIDs rmElemIds; // IDs of elems to remove
7977 SMESHDS_Mesh* aMesh = GetMeshDS();
7979 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7980 while ( groupsIt != theGroupsOfElementsID.end() ) {
7981 TListOfIDs& aGroupOfElemID = *groupsIt;
7982 aGroupOfElemID.sort();
7983 int elemIDToKeep = aGroupOfElemID.front();
7984 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7985 aGroupOfElemID.pop_front();
7986 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7987 while ( idIt != aGroupOfElemID.end() ) {
7988 int elemIDToRemove = *idIt;
7989 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7990 // add the kept element in groups of removed one (PAL15188)
7991 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7992 rmElemIds.push_back( elemIDToRemove );
7998 Remove( rmElemIds, false );
8001 //=======================================================================
8002 //function : MergeEqualElements
8003 //purpose : Remove all but one of elements built on the same nodes.
8004 //=======================================================================
8006 void SMESH_MeshEditor::MergeEqualElements()
8008 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8009 to merge equal elements in the whole mesh */
8010 TListOfListOfElementsID aGroupsOfElementsID;
8011 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8012 MergeElements(aGroupsOfElementsID);
8015 //=======================================================================
8016 //function : FindFaceInSet
8017 //purpose : Return a face having linked nodes n1 and n2 and which is
8018 // - not in avoidSet,
8019 // - in elemSet provided that !elemSet.empty()
8020 // i1 and i2 optionally returns indices of n1 and n2
8021 //=======================================================================
8023 const SMDS_MeshElement*
8024 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8025 const SMDS_MeshNode* n2,
8026 const TIDSortedElemSet& elemSet,
8027 const TIDSortedElemSet& avoidSet,
8033 const SMDS_MeshElement* face = 0;
8035 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8036 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8037 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8039 //MESSAGE("in while ( invElemIt->more() && !face )");
8040 const SMDS_MeshElement* elem = invElemIt->next();
8041 if (avoidSet.count( elem ))
8043 if ( !elemSet.empty() && !elemSet.count( elem ))
8046 i1 = elem->GetNodeIndex( n1 );
8047 // find a n2 linked to n1
8048 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8049 for ( int di = -1; di < 2 && !face; di += 2 )
8051 i2 = (i1+di+nbN) % nbN;
8052 if ( elem->GetNode( i2 ) == n2 )
8055 if ( !face && elem->IsQuadratic())
8057 // analysis for quadratic elements using all nodes
8058 const SMDS_VtkFace* F =
8059 dynamic_cast<const SMDS_VtkFace*>(elem);
8060 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8061 // use special nodes iterator
8062 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8063 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8064 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8066 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8067 if ( n1 == prevN && n2 == n )
8071 else if ( n2 == prevN && n1 == n )
8073 face = elem; swap( i1, i2 );
8079 if ( n1ind ) *n1ind = i1;
8080 if ( n2ind ) *n2ind = i2;
8084 //=======================================================================
8085 //function : findAdjacentFace
8087 //=======================================================================
8089 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8090 const SMDS_MeshNode* n2,
8091 const SMDS_MeshElement* elem)
8093 TIDSortedElemSet elemSet, avoidSet;
8095 avoidSet.insert ( elem );
8096 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8099 //=======================================================================
8100 //function : FindFreeBorder
8102 //=======================================================================
8104 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8106 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8107 const SMDS_MeshNode* theSecondNode,
8108 const SMDS_MeshNode* theLastNode,
8109 list< const SMDS_MeshNode* > & theNodes,
8110 list< const SMDS_MeshElement* >& theFaces)
8112 if ( !theFirstNode || !theSecondNode )
8114 // find border face between theFirstNode and theSecondNode
8115 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8119 theFaces.push_back( curElem );
8120 theNodes.push_back( theFirstNode );
8121 theNodes.push_back( theSecondNode );
8123 //vector<const SMDS_MeshNode*> nodes;
8124 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8125 TIDSortedElemSet foundElems;
8126 bool needTheLast = ( theLastNode != 0 );
8128 while ( nStart != theLastNode ) {
8129 if ( nStart == theFirstNode )
8130 return !needTheLast;
8132 // find all free border faces sharing form nStart
8134 list< const SMDS_MeshElement* > curElemList;
8135 list< const SMDS_MeshNode* > nStartList;
8136 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8137 while ( invElemIt->more() ) {
8138 const SMDS_MeshElement* e = invElemIt->next();
8139 if ( e == curElem || foundElems.insert( e ).second ) {
8141 int iNode = 0, nbNodes = e->NbNodes();
8142 //const SMDS_MeshNode* nodes[nbNodes+1];
8143 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8145 if(e->IsQuadratic()) {
8146 const SMDS_VtkFace* F =
8147 dynamic_cast<const SMDS_VtkFace*>(e);
8148 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8149 // use special nodes iterator
8150 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8151 while( anIter->more() ) {
8152 nodes[ iNode++ ] = cast2Node(anIter->next());
8156 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8157 while ( nIt->more() )
8158 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8160 nodes[ iNode ] = nodes[ 0 ];
8162 for ( iNode = 0; iNode < nbNodes; iNode++ )
8163 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8164 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8165 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8167 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8168 curElemList.push_back( e );
8172 // analyse the found
8174 int nbNewBorders = curElemList.size();
8175 if ( nbNewBorders == 0 ) {
8176 // no free border furthermore
8177 return !needTheLast;
8179 else if ( nbNewBorders == 1 ) {
8180 // one more element found
8182 nStart = nStartList.front();
8183 curElem = curElemList.front();
8184 theFaces.push_back( curElem );
8185 theNodes.push_back( nStart );
8188 // several continuations found
8189 list< const SMDS_MeshElement* >::iterator curElemIt;
8190 list< const SMDS_MeshNode* >::iterator nStartIt;
8191 // check if one of them reached the last node
8192 if ( needTheLast ) {
8193 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8194 curElemIt!= curElemList.end();
8195 curElemIt++, nStartIt++ )
8196 if ( *nStartIt == theLastNode ) {
8197 theFaces.push_back( *curElemIt );
8198 theNodes.push_back( *nStartIt );
8202 // find the best free border by the continuations
8203 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8204 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8205 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8206 curElemIt!= curElemList.end();
8207 curElemIt++, nStartIt++ )
8209 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8210 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8211 // find one more free border
8212 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8216 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8217 // choice: clear a worse one
8218 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8219 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8220 contNodes[ iWorse ].clear();
8221 contFaces[ iWorse ].clear();
8224 if ( contNodes[0].empty() && contNodes[1].empty() )
8227 // append the best free border
8228 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8229 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8230 theNodes.pop_back(); // remove nIgnore
8231 theNodes.pop_back(); // remove nStart
8232 theFaces.pop_back(); // remove curElem
8233 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8234 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8235 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8236 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8239 } // several continuations found
8240 } // while ( nStart != theLastNode )
8245 //=======================================================================
8246 //function : CheckFreeBorderNodes
8247 //purpose : Return true if the tree nodes are on a free border
8248 //=======================================================================
8250 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8251 const SMDS_MeshNode* theNode2,
8252 const SMDS_MeshNode* theNode3)
8254 list< const SMDS_MeshNode* > nodes;
8255 list< const SMDS_MeshElement* > faces;
8256 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8259 //=======================================================================
8260 //function : SewFreeBorder
8262 //=======================================================================
8264 SMESH_MeshEditor::Sew_Error
8265 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8266 const SMDS_MeshNode* theBordSecondNode,
8267 const SMDS_MeshNode* theBordLastNode,
8268 const SMDS_MeshNode* theSideFirstNode,
8269 const SMDS_MeshNode* theSideSecondNode,
8270 const SMDS_MeshNode* theSideThirdNode,
8271 const bool theSideIsFreeBorder,
8272 const bool toCreatePolygons,
8273 const bool toCreatePolyedrs)
8275 myLastCreatedElems.Clear();
8276 myLastCreatedNodes.Clear();
8278 MESSAGE("::SewFreeBorder()");
8279 Sew_Error aResult = SEW_OK;
8281 // ====================================
8282 // find side nodes and elements
8283 // ====================================
8285 list< const SMDS_MeshNode* > nSide[ 2 ];
8286 list< const SMDS_MeshElement* > eSide[ 2 ];
8287 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8288 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8292 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8293 nSide[0], eSide[0])) {
8294 MESSAGE(" Free Border 1 not found " );
8295 aResult = SEW_BORDER1_NOT_FOUND;
8297 if (theSideIsFreeBorder) {
8300 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8301 nSide[1], eSide[1])) {
8302 MESSAGE(" Free Border 2 not found " );
8303 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8306 if ( aResult != SEW_OK )
8309 if (!theSideIsFreeBorder) {
8313 // -------------------------------------------------------------------------
8315 // 1. If nodes to merge are not coincident, move nodes of the free border
8316 // from the coord sys defined by the direction from the first to last
8317 // nodes of the border to the correspondent sys of the side 2
8318 // 2. On the side 2, find the links most co-directed with the correspondent
8319 // links of the free border
8320 // -------------------------------------------------------------------------
8322 // 1. Since sewing may break if there are volumes to split on the side 2,
8323 // we wont move nodes but just compute new coordinates for them
8324 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8325 TNodeXYZMap nBordXYZ;
8326 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8327 list< const SMDS_MeshNode* >::iterator nBordIt;
8329 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8330 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8331 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8332 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8333 double tol2 = 1.e-8;
8334 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8335 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8336 // Need node movement.
8338 // find X and Z axes to create trsf
8339 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8341 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8343 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8346 gp_Ax3 toBordAx( Pb1, Zb, X );
8347 gp_Ax3 fromSideAx( Ps1, Zs, X );
8348 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8350 gp_Trsf toBordSys, fromSide2Sys;
8351 toBordSys.SetTransformation( toBordAx );
8352 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8353 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8356 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8357 const SMDS_MeshNode* n = *nBordIt;
8358 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8359 toBordSys.Transforms( xyz );
8360 fromSide2Sys.Transforms( xyz );
8361 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8365 // just insert nodes XYZ in the nBordXYZ map
8366 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8367 const SMDS_MeshNode* n = *nBordIt;
8368 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8372 // 2. On the side 2, find the links most co-directed with the correspondent
8373 // links of the free border
8375 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8376 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8377 sideNodes.push_back( theSideFirstNode );
8379 bool hasVolumes = false;
8380 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8381 set<long> foundSideLinkIDs, checkedLinkIDs;
8382 SMDS_VolumeTool volume;
8383 //const SMDS_MeshNode* faceNodes[ 4 ];
8385 const SMDS_MeshNode* sideNode;
8386 const SMDS_MeshElement* sideElem;
8387 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8388 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8389 nBordIt = bordNodes.begin();
8391 // border node position and border link direction to compare with
8392 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8393 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8394 // choose next side node by link direction or by closeness to
8395 // the current border node:
8396 bool searchByDir = ( *nBordIt != theBordLastNode );
8398 // find the next node on the Side 2
8400 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8402 checkedLinkIDs.clear();
8403 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8405 // loop on inverse elements of current node (prevSideNode) on the Side 2
8406 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8407 while ( invElemIt->more() )
8409 const SMDS_MeshElement* elem = invElemIt->next();
8410 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8411 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8412 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8413 bool isVolume = volume.Set( elem );
8414 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8415 if ( isVolume ) // --volume
8417 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8418 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8419 if(elem->IsQuadratic()) {
8420 const SMDS_VtkFace* F =
8421 dynamic_cast<const SMDS_VtkFace*>(elem);
8422 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8423 // use special nodes iterator
8424 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8425 while( anIter->more() ) {
8426 nodes[ iNode ] = cast2Node(anIter->next());
8427 if ( nodes[ iNode++ ] == prevSideNode )
8428 iPrevNode = iNode - 1;
8432 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8433 while ( nIt->more() ) {
8434 nodes[ iNode ] = cast2Node( nIt->next() );
8435 if ( nodes[ iNode++ ] == prevSideNode )
8436 iPrevNode = iNode - 1;
8439 // there are 2 links to check
8444 // loop on links, to be precise, on the second node of links
8445 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8446 const SMDS_MeshNode* n = nodes[ iNode ];
8448 if ( !volume.IsLinked( n, prevSideNode ))
8452 if ( iNode ) // a node before prevSideNode
8453 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8454 else // a node after prevSideNode
8455 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8457 // check if this link was already used
8458 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8459 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8460 if (!isJustChecked &&
8461 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8463 // test a link geometrically
8464 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8465 bool linkIsBetter = false;
8466 double dot = 0.0, dist = 0.0;
8467 if ( searchByDir ) { // choose most co-directed link
8468 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8469 linkIsBetter = ( dot > maxDot );
8471 else { // choose link with the node closest to bordPos
8472 dist = ( nextXYZ - bordPos ).SquareModulus();
8473 linkIsBetter = ( dist < minDist );
8475 if ( linkIsBetter ) {
8484 } // loop on inverse elements of prevSideNode
8487 MESSAGE(" Cant find path by links of the Side 2 ");
8488 return SEW_BAD_SIDE_NODES;
8490 sideNodes.push_back( sideNode );
8491 sideElems.push_back( sideElem );
8492 foundSideLinkIDs.insert ( linkID );
8493 prevSideNode = sideNode;
8495 if ( *nBordIt == theBordLastNode )
8496 searchByDir = false;
8498 // find the next border link to compare with
8499 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8500 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8501 // move to next border node if sideNode is before forward border node (bordPos)
8502 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8503 prevBordNode = *nBordIt;
8505 bordPos = nBordXYZ[ *nBordIt ];
8506 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8507 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8511 while ( sideNode != theSideSecondNode );
8513 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8514 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8515 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8517 } // end nodes search on the side 2
8519 // ============================
8520 // sew the border to the side 2
8521 // ============================
8523 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8524 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8526 TListOfListOfNodes nodeGroupsToMerge;
8527 if ( nbNodes[0] == nbNodes[1] ||
8528 ( theSideIsFreeBorder && !theSideThirdNode)) {
8530 // all nodes are to be merged
8532 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8533 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8534 nIt[0]++, nIt[1]++ )
8536 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8537 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8538 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8543 // insert new nodes into the border and the side to get equal nb of segments
8545 // get normalized parameters of nodes on the borders
8546 //double param[ 2 ][ maxNbNodes ];
8548 param[0] = new double [ maxNbNodes ];
8549 param[1] = new double [ maxNbNodes ];
8551 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8552 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8553 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8554 const SMDS_MeshNode* nPrev = *nIt;
8555 double bordLength = 0;
8556 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8557 const SMDS_MeshNode* nCur = *nIt;
8558 gp_XYZ segment (nCur->X() - nPrev->X(),
8559 nCur->Y() - nPrev->Y(),
8560 nCur->Z() - nPrev->Z());
8561 double segmentLen = segment.Modulus();
8562 bordLength += segmentLen;
8563 param[ iBord ][ iNode ] = bordLength;
8566 // normalize within [0,1]
8567 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8568 param[ iBord ][ iNode ] /= bordLength;
8572 // loop on border segments
8573 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8574 int i[ 2 ] = { 0, 0 };
8575 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8576 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8578 TElemOfNodeListMap insertMap;
8579 TElemOfNodeListMap::iterator insertMapIt;
8581 // key: elem to insert nodes into
8582 // value: 2 nodes to insert between + nodes to be inserted
8584 bool next[ 2 ] = { false, false };
8586 // find min adjacent segment length after sewing
8587 double nextParam = 10., prevParam = 0;
8588 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8589 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8590 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8591 if ( i[ iBord ] > 0 )
8592 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8594 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8595 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8596 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8598 // choose to insert or to merge nodes
8599 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8600 if ( Abs( du ) <= minSegLen * 0.2 ) {
8603 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8604 const SMDS_MeshNode* n0 = *nIt[0];
8605 const SMDS_MeshNode* n1 = *nIt[1];
8606 nodeGroupsToMerge.back().push_back( n1 );
8607 nodeGroupsToMerge.back().push_back( n0 );
8608 // position of node of the border changes due to merge
8609 param[ 0 ][ i[0] ] += du;
8610 // move n1 for the sake of elem shape evaluation during insertion.
8611 // n1 will be removed by MergeNodes() anyway
8612 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8613 next[0] = next[1] = true;
8618 int intoBord = ( du < 0 ) ? 0 : 1;
8619 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8620 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8621 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8622 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8623 if ( intoBord == 1 ) {
8624 // move node of the border to be on a link of elem of the side
8625 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8626 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8627 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8628 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8629 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8631 insertMapIt = insertMap.find( elem );
8632 bool notFound = ( insertMapIt == insertMap.end() );
8633 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8635 // insert into another link of the same element:
8636 // 1. perform insertion into the other link of the elem
8637 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8638 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8639 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8640 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8641 // 2. perform insertion into the link of adjacent faces
8643 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8645 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8649 if (toCreatePolyedrs) {
8650 // perform insertion into the links of adjacent volumes
8651 UpdateVolumes(n12, n22, nodeList);
8653 // 3. find an element appeared on n1 and n2 after the insertion
8654 insertMap.erase( elem );
8655 elem = findAdjacentFace( n1, n2, 0 );
8657 if ( notFound || otherLink ) {
8658 // add element and nodes of the side into the insertMap
8659 insertMapIt = insertMap.insert
8660 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8661 (*insertMapIt).second.push_back( n1 );
8662 (*insertMapIt).second.push_back( n2 );
8664 // add node to be inserted into elem
8665 (*insertMapIt).second.push_back( nIns );
8666 next[ 1 - intoBord ] = true;
8669 // go to the next segment
8670 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8671 if ( next[ iBord ] ) {
8672 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8674 nPrev[ iBord ] = *nIt[ iBord ];
8675 nIt[ iBord ]++; i[ iBord ]++;
8679 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8681 // perform insertion of nodes into elements
8683 for (insertMapIt = insertMap.begin();
8684 insertMapIt != insertMap.end();
8687 const SMDS_MeshElement* elem = (*insertMapIt).first;
8688 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8689 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8690 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8692 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8694 if ( !theSideIsFreeBorder ) {
8695 // look for and insert nodes into the faces adjacent to elem
8697 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8699 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8704 if (toCreatePolyedrs) {
8705 // perform insertion into the links of adjacent volumes
8706 UpdateVolumes(n1, n2, nodeList);
8712 } // end: insert new nodes
8714 MergeNodes ( nodeGroupsToMerge );
8719 //=======================================================================
8720 //function : InsertNodesIntoLink
8721 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8722 // and theBetweenNode2 and split theElement
8723 //=======================================================================
8725 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8726 const SMDS_MeshNode* theBetweenNode1,
8727 const SMDS_MeshNode* theBetweenNode2,
8728 list<const SMDS_MeshNode*>& theNodesToInsert,
8729 const bool toCreatePoly)
8731 if ( theFace->GetType() != SMDSAbs_Face ) return;
8733 // find indices of 2 link nodes and of the rest nodes
8734 int iNode = 0, il1, il2, i3, i4;
8735 il1 = il2 = i3 = i4 = -1;
8736 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8737 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8739 if(theFace->IsQuadratic()) {
8740 const SMDS_VtkFace* F =
8741 dynamic_cast<const SMDS_VtkFace*>(theFace);
8742 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8743 // use special nodes iterator
8744 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8745 while( anIter->more() ) {
8746 const SMDS_MeshNode* n = cast2Node(anIter->next());
8747 if ( n == theBetweenNode1 )
8749 else if ( n == theBetweenNode2 )
8755 nodes[ iNode++ ] = n;
8759 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8760 while ( nodeIt->more() ) {
8761 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8762 if ( n == theBetweenNode1 )
8764 else if ( n == theBetweenNode2 )
8770 nodes[ iNode++ ] = n;
8773 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8776 // arrange link nodes to go one after another regarding the face orientation
8777 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8778 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8783 aNodesToInsert.reverse();
8785 // check that not link nodes of a quadrangles are in good order
8786 int nbFaceNodes = theFace->NbNodes();
8787 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8793 if (toCreatePoly || theFace->IsPoly()) {
8796 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8798 // add nodes of face up to first node of link
8801 if(theFace->IsQuadratic()) {
8802 const SMDS_VtkFace* F =
8803 dynamic_cast<const SMDS_VtkFace*>(theFace);
8804 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8805 // use special nodes iterator
8806 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8807 while( anIter->more() && !isFLN ) {
8808 const SMDS_MeshNode* n = cast2Node(anIter->next());
8809 poly_nodes[iNode++] = n;
8810 if (n == nodes[il1]) {
8814 // add nodes to insert
8815 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8816 for (; nIt != aNodesToInsert.end(); nIt++) {
8817 poly_nodes[iNode++] = *nIt;
8819 // add nodes of face starting from last node of link
8820 while ( anIter->more() ) {
8821 poly_nodes[iNode++] = cast2Node(anIter->next());
8825 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8826 while ( nodeIt->more() && !isFLN ) {
8827 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8828 poly_nodes[iNode++] = n;
8829 if (n == nodes[il1]) {
8833 // add nodes to insert
8834 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8835 for (; nIt != aNodesToInsert.end(); nIt++) {
8836 poly_nodes[iNode++] = *nIt;
8838 // add nodes of face starting from last node of link
8839 while ( nodeIt->more() ) {
8840 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8841 poly_nodes[iNode++] = n;
8845 // edit or replace the face
8846 SMESHDS_Mesh *aMesh = GetMeshDS();
8848 if (theFace->IsPoly()) {
8849 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8852 int aShapeId = FindShape( theFace );
8854 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8855 myLastCreatedElems.Append(newElem);
8856 if ( aShapeId && newElem )
8857 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8859 aMesh->RemoveElement(theFace);
8864 SMESHDS_Mesh *aMesh = GetMeshDS();
8865 if( !theFace->IsQuadratic() ) {
8867 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8868 int nbLinkNodes = 2 + aNodesToInsert.size();
8869 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8870 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8871 linkNodes[ 0 ] = nodes[ il1 ];
8872 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8873 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8874 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8875 linkNodes[ iNode++ ] = *nIt;
8877 // decide how to split a quadrangle: compare possible variants
8878 // and choose which of splits to be a quadrangle
8879 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8880 if ( nbFaceNodes == 3 ) {
8881 iBestQuad = nbSplits;
8884 else if ( nbFaceNodes == 4 ) {
8885 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8886 double aBestRate = DBL_MAX;
8887 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8889 double aBadRate = 0;
8890 // evaluate elements quality
8891 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8892 if ( iSplit == iQuad ) {
8893 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8897 aBadRate += getBadRate( &quad, aCrit );
8900 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8902 nodes[ iSplit < iQuad ? i4 : i3 ]);
8903 aBadRate += getBadRate( &tria, aCrit );
8907 if ( aBadRate < aBestRate ) {
8909 aBestRate = aBadRate;
8914 // create new elements
8915 int aShapeId = FindShape( theFace );
8918 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8919 SMDS_MeshElement* newElem = 0;
8920 if ( iSplit == iBestQuad )
8921 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8926 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8928 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8929 myLastCreatedElems.Append(newElem);
8930 if ( aShapeId && newElem )
8931 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8934 // change nodes of theFace
8935 const SMDS_MeshNode* newNodes[ 4 ];
8936 newNodes[ 0 ] = linkNodes[ i1 ];
8937 newNodes[ 1 ] = linkNodes[ i2 ];
8938 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8939 newNodes[ 3 ] = nodes[ i4 ];
8940 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8941 const SMDS_MeshElement* newElem = 0;
8942 if (iSplit == iBestQuad)
8943 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8945 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8946 myLastCreatedElems.Append(newElem);
8947 if ( aShapeId && newElem )
8948 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8949 } // end if(!theFace->IsQuadratic())
8950 else { // theFace is quadratic
8951 // we have to split theFace on simple triangles and one simple quadrangle
8953 int nbshift = tmp*2;
8954 // shift nodes in nodes[] by nbshift
8956 for(i=0; i<nbshift; i++) {
8957 const SMDS_MeshNode* n = nodes[0];
8958 for(j=0; j<nbFaceNodes-1; j++) {
8959 nodes[j] = nodes[j+1];
8961 nodes[nbFaceNodes-1] = n;
8963 il1 = il1 - nbshift;
8964 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8965 // n0 n1 n2 n0 n1 n2
8966 // +-----+-----+ +-----+-----+
8975 // create new elements
8976 int aShapeId = FindShape( theFace );
8979 if(nbFaceNodes==6) { // quadratic triangle
8980 SMDS_MeshElement* newElem =
8981 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8982 myLastCreatedElems.Append(newElem);
8983 if ( aShapeId && newElem )
8984 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8985 if(theFace->IsMediumNode(nodes[il1])) {
8986 // create quadrangle
8987 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8988 myLastCreatedElems.Append(newElem);
8989 if ( aShapeId && newElem )
8990 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8996 // create quadrangle
8997 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8998 myLastCreatedElems.Append(newElem);
8999 if ( aShapeId && newElem )
9000 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9006 else { // nbFaceNodes==8 - quadratic quadrangle
9007 SMDS_MeshElement* newElem =
9008 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9009 myLastCreatedElems.Append(newElem);
9010 if ( aShapeId && newElem )
9011 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9012 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9013 myLastCreatedElems.Append(newElem);
9014 if ( aShapeId && newElem )
9015 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9016 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9017 myLastCreatedElems.Append(newElem);
9018 if ( aShapeId && newElem )
9019 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9020 if(theFace->IsMediumNode(nodes[il1])) {
9021 // create quadrangle
9022 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9023 myLastCreatedElems.Append(newElem);
9024 if ( aShapeId && newElem )
9025 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9031 // create quadrangle
9032 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9033 myLastCreatedElems.Append(newElem);
9034 if ( aShapeId && newElem )
9035 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9041 // create needed triangles using n1,n2,n3 and inserted nodes
9042 int nbn = 2 + aNodesToInsert.size();
9043 //const SMDS_MeshNode* aNodes[nbn];
9044 vector<const SMDS_MeshNode*> aNodes(nbn);
9045 aNodes[0] = nodes[n1];
9046 aNodes[nbn-1] = nodes[n2];
9047 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9048 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9049 aNodes[iNode++] = *nIt;
9051 for(i=1; i<nbn; i++) {
9052 SMDS_MeshElement* newElem =
9053 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9054 myLastCreatedElems.Append(newElem);
9055 if ( aShapeId && newElem )
9056 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9060 aMesh->RemoveElement(theFace);
9063 //=======================================================================
9064 //function : UpdateVolumes
9066 //=======================================================================
9067 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9068 const SMDS_MeshNode* theBetweenNode2,
9069 list<const SMDS_MeshNode*>& theNodesToInsert)
9071 myLastCreatedElems.Clear();
9072 myLastCreatedNodes.Clear();
9074 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9075 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9076 const SMDS_MeshElement* elem = invElemIt->next();
9078 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9079 SMDS_VolumeTool aVolume (elem);
9080 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9083 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9084 int iface, nbFaces = aVolume.NbFaces();
9085 vector<const SMDS_MeshNode *> poly_nodes;
9086 vector<int> quantities (nbFaces);
9088 for (iface = 0; iface < nbFaces; iface++) {
9089 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9090 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9091 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9093 for (int inode = 0; inode < nbFaceNodes; inode++) {
9094 poly_nodes.push_back(faceNodes[inode]);
9096 if (nbInserted == 0) {
9097 if (faceNodes[inode] == theBetweenNode1) {
9098 if (faceNodes[inode + 1] == theBetweenNode2) {
9099 nbInserted = theNodesToInsert.size();
9101 // add nodes to insert
9102 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9103 for (; nIt != theNodesToInsert.end(); nIt++) {
9104 poly_nodes.push_back(*nIt);
9108 else if (faceNodes[inode] == theBetweenNode2) {
9109 if (faceNodes[inode + 1] == theBetweenNode1) {
9110 nbInserted = theNodesToInsert.size();
9112 // add nodes to insert in reversed order
9113 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9115 for (; nIt != theNodesToInsert.begin(); nIt--) {
9116 poly_nodes.push_back(*nIt);
9118 poly_nodes.push_back(*nIt);
9125 quantities[iface] = nbFaceNodes + nbInserted;
9128 // Replace or update the volume
9129 SMESHDS_Mesh *aMesh = GetMeshDS();
9131 if (elem->IsPoly()) {
9132 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9136 int aShapeId = FindShape( elem );
9138 SMDS_MeshElement* newElem =
9139 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9140 myLastCreatedElems.Append(newElem);
9141 if (aShapeId && newElem)
9142 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9144 aMesh->RemoveElement(elem);
9149 //=======================================================================
9151 * \brief Convert elements contained in a submesh to quadratic
9152 * \retval int - nb of checked elements
9154 //=======================================================================
9156 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9157 SMESH_MesherHelper& theHelper,
9158 const bool theForce3d)
9161 if( !theSm ) return nbElem;
9163 vector<int> nbNodeInFaces;
9164 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9165 while(ElemItr->more())
9168 const SMDS_MeshElement* elem = ElemItr->next();
9169 if( !elem || elem->IsQuadratic() ) continue;
9171 int id = elem->GetID();
9172 //MESSAGE("elem " << id);
9173 id = 0; // get a free number for new elements
9174 int nbNodes = elem->NbNodes();
9175 SMDSAbs_ElementType aType = elem->GetType();
9177 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9178 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9179 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9181 const SMDS_MeshElement* NewElem = 0;
9187 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9195 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9198 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9201 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9206 case SMDSAbs_Volume :
9211 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9214 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9217 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9220 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9221 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9224 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9231 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9233 theSm->AddElement( NewElem );
9235 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9237 // if (!GetMeshDS()->isCompacted())
9238 // GetMeshDS()->compactMesh();
9242 //=======================================================================
9243 //function : ConvertToQuadratic
9245 //=======================================================================
9246 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9248 SMESHDS_Mesh* meshDS = GetMeshDS();
9250 SMESH_MesherHelper aHelper(*myMesh);
9251 aHelper.SetIsQuadratic( true );
9253 int nbCheckedElems = 0;
9254 if ( myMesh->HasShapeToMesh() )
9256 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9258 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9259 while ( smIt->more() ) {
9260 SMESH_subMesh* sm = smIt->next();
9261 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9262 aHelper.SetSubShape( sm->GetSubShape() );
9263 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9268 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9269 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9271 SMESHDS_SubMesh *smDS = 0;
9272 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9273 while(aEdgeItr->more())
9275 const SMDS_MeshEdge* edge = aEdgeItr->next();
9276 if(edge && !edge->IsQuadratic())
9278 int id = edge->GetID();
9279 //MESSAGE("edge->GetID() " << id);
9280 const SMDS_MeshNode* n1 = edge->GetNode(0);
9281 const SMDS_MeshNode* n2 = edge->GetNode(1);
9283 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9285 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9286 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9289 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9290 while(aFaceItr->more())
9292 const SMDS_MeshFace* face = aFaceItr->next();
9293 if(!face || face->IsQuadratic() ) continue;
9295 int id = face->GetID();
9296 int nbNodes = face->NbNodes();
9297 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9299 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9301 SMDS_MeshFace * NewFace = 0;
9305 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9308 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9311 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9313 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9315 vector<int> nbNodeInFaces;
9316 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9317 while(aVolumeItr->more())
9319 const SMDS_MeshVolume* volume = aVolumeItr->next();
9320 if(!volume || volume->IsQuadratic() ) continue;
9322 int id = volume->GetID();
9323 int nbNodes = volume->NbNodes();
9324 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9325 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9326 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9328 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9330 SMDS_MeshVolume * NewVolume = 0;
9334 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9335 nodes[3], id, theForce3d );
9338 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9339 nodes[3], nodes[4], id, theForce3d);
9342 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9343 nodes[3], nodes[4], nodes[5], id, theForce3d);
9346 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9347 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9350 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9352 ReplaceElemInGroups(volume, NewVolume, meshDS);
9356 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9357 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9358 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9359 aHelper.FixQuadraticElements();
9361 if (!GetMeshDS()->isCompacted())
9362 GetMeshDS()->compactMesh();
9365 //=======================================================================
9367 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9368 * \retval int - nb of checked elements
9370 //=======================================================================
9372 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9373 SMDS_ElemIteratorPtr theItr,
9374 const int theShapeID)
9377 SMESHDS_Mesh* meshDS = GetMeshDS();
9378 const bool notFromGroups = false;
9380 while( theItr->more() )
9382 const SMDS_MeshElement* elem = theItr->next();
9384 if( elem && elem->IsQuadratic())
9386 int id = elem->GetID();
9387 int nbNodes = elem->NbNodes();
9388 vector<const SMDS_MeshNode *> nodes, mediumNodes;
9389 nodes.reserve( nbNodes );
9390 mediumNodes.reserve( nbNodes );
9392 for(int i = 0; i < nbNodes; i++)
9394 const SMDS_MeshNode* n = elem->GetNode(i);
9396 if( elem->IsMediumNode( n ) )
9397 mediumNodes.push_back( n );
9399 nodes.push_back( n );
9401 if( nodes.empty() ) continue;
9402 SMDSAbs_ElementType aType = elem->GetType();
9404 //remove old quadratic element
9405 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9407 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9408 ReplaceElemInGroups(elem, NewElem, meshDS);
9409 if( theSm && NewElem )
9410 theSm->AddElement( NewElem );
9412 // remove medium nodes
9413 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9414 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9415 const SMDS_MeshNode* n = *nIt;
9416 if ( n->NbInverseElements() == 0 ) {
9417 if ( n->getshapeId() != theShapeID )
9418 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9419 ( n->getshapeId() ));
9421 meshDS->RemoveFreeNode( n, theSm );
9429 //=======================================================================
9430 //function : ConvertFromQuadratic
9432 //=======================================================================
9433 bool SMESH_MeshEditor::ConvertFromQuadratic()
9435 int nbCheckedElems = 0;
9436 if ( myMesh->HasShapeToMesh() )
9438 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9440 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9441 while ( smIt->more() ) {
9442 SMESH_subMesh* sm = smIt->next();
9443 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9444 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9450 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9451 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9453 SMESHDS_SubMesh *aSM = 0;
9454 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9460 //=======================================================================
9461 //function : SewSideElements
9463 //=======================================================================
9465 SMESH_MeshEditor::Sew_Error
9466 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9467 TIDSortedElemSet& theSide2,
9468 const SMDS_MeshNode* theFirstNode1,
9469 const SMDS_MeshNode* theFirstNode2,
9470 const SMDS_MeshNode* theSecondNode1,
9471 const SMDS_MeshNode* theSecondNode2)
9473 myLastCreatedElems.Clear();
9474 myLastCreatedNodes.Clear();
9476 MESSAGE ("::::SewSideElements()");
9477 if ( theSide1.size() != theSide2.size() )
9478 return SEW_DIFF_NB_OF_ELEMENTS;
9480 Sew_Error aResult = SEW_OK;
9482 // 1. Build set of faces representing each side
9483 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9484 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9486 // =======================================================================
9487 // 1. Build set of faces representing each side:
9488 // =======================================================================
9489 // a. build set of nodes belonging to faces
9490 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9491 // c. create temporary faces representing side of volumes if correspondent
9492 // face does not exist
9494 SMESHDS_Mesh* aMesh = GetMeshDS();
9495 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9496 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9497 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9498 set<const SMDS_MeshElement*> volSet1, volSet2;
9499 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9500 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9501 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9502 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9503 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9504 int iSide, iFace, iNode;
9506 list<const SMDS_MeshElement* > tempFaceList;
9507 for ( iSide = 0; iSide < 2; iSide++ ) {
9508 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9509 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9510 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9511 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9512 set<const SMDS_MeshElement*>::iterator vIt;
9513 TIDSortedElemSet::iterator eIt;
9514 set<const SMDS_MeshNode*>::iterator nIt;
9516 // check that given nodes belong to given elements
9517 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9518 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9519 int firstIndex = -1, secondIndex = -1;
9520 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9521 const SMDS_MeshElement* elem = *eIt;
9522 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9523 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9524 if ( firstIndex > -1 && secondIndex > -1 ) break;
9526 if ( firstIndex < 0 || secondIndex < 0 ) {
9527 // we can simply return until temporary faces created
9528 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9531 // -----------------------------------------------------------
9532 // 1a. Collect nodes of existing faces
9533 // and build set of face nodes in order to detect missing
9534 // faces corresponding to sides of volumes
9535 // -----------------------------------------------------------
9537 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9539 // loop on the given element of a side
9540 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9541 //const SMDS_MeshElement* elem = *eIt;
9542 const SMDS_MeshElement* elem = *eIt;
9543 if ( elem->GetType() == SMDSAbs_Face ) {
9544 faceSet->insert( elem );
9545 set <const SMDS_MeshNode*> faceNodeSet;
9546 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9547 while ( nodeIt->more() ) {
9548 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9549 nodeSet->insert( n );
9550 faceNodeSet.insert( n );
9552 setOfFaceNodeSet.insert( faceNodeSet );
9554 else if ( elem->GetType() == SMDSAbs_Volume )
9555 volSet->insert( elem );
9557 // ------------------------------------------------------------------------------
9558 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9559 // ------------------------------------------------------------------------------
9561 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9562 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9563 while ( fIt->more() ) { // loop on faces sharing a node
9564 const SMDS_MeshElement* f = fIt->next();
9565 if ( faceSet->find( f ) == faceSet->end() ) {
9566 // check if all nodes are in nodeSet and
9567 // complete setOfFaceNodeSet if they are
9568 set <const SMDS_MeshNode*> faceNodeSet;
9569 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9570 bool allInSet = true;
9571 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9572 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9573 if ( nodeSet->find( n ) == nodeSet->end() )
9576 faceNodeSet.insert( n );
9579 faceSet->insert( f );
9580 setOfFaceNodeSet.insert( faceNodeSet );
9586 // -------------------------------------------------------------------------
9587 // 1c. Create temporary faces representing sides of volumes if correspondent
9588 // face does not exist
9589 // -------------------------------------------------------------------------
9591 if ( !volSet->empty() ) {
9592 //int nodeSetSize = nodeSet->size();
9594 // loop on given volumes
9595 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9596 SMDS_VolumeTool vol (*vIt);
9597 // loop on volume faces: find free faces
9598 // --------------------------------------
9599 list<const SMDS_MeshElement* > freeFaceList;
9600 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9601 if ( !vol.IsFreeFace( iFace ))
9603 // check if there is already a face with same nodes in a face set
9604 const SMDS_MeshElement* aFreeFace = 0;
9605 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9606 int nbNodes = vol.NbFaceNodes( iFace );
9607 set <const SMDS_MeshNode*> faceNodeSet;
9608 vol.GetFaceNodes( iFace, faceNodeSet );
9609 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9611 // no such a face is given but it still can exist, check it
9612 if ( nbNodes == 3 ) {
9613 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9615 else if ( nbNodes == 4 ) {
9616 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9619 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9620 aFreeFace = aMesh->FindFace(poly_nodes);
9624 // create a temporary face
9625 if ( nbNodes == 3 ) {
9626 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9627 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9629 else if ( nbNodes == 4 ) {
9630 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9631 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9634 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9635 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9636 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9640 freeFaceList.push_back( aFreeFace );
9641 tempFaceList.push_back( aFreeFace );
9644 } // loop on faces of a volume
9646 // choose one of several free faces
9647 // --------------------------------------
9648 if ( freeFaceList.size() > 1 ) {
9649 // choose a face having max nb of nodes shared by other elems of a side
9650 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9651 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9652 while ( fIt != freeFaceList.end() ) { // loop on free faces
9653 int nbSharedNodes = 0;
9654 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9655 while ( nodeIt->more() ) { // loop on free face nodes
9656 const SMDS_MeshNode* n =
9657 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9658 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9659 while ( invElemIt->more() ) {
9660 const SMDS_MeshElement* e = invElemIt->next();
9661 if ( faceSet->find( e ) != faceSet->end() )
9663 if ( elemSet->find( e ) != elemSet->end() )
9667 if ( nbSharedNodes >= maxNbNodes ) {
9668 maxNbNodes = nbSharedNodes;
9672 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9674 if ( freeFaceList.size() > 1 )
9676 // could not choose one face, use another way
9677 // choose a face most close to the bary center of the opposite side
9678 gp_XYZ aBC( 0., 0., 0. );
9679 set <const SMDS_MeshNode*> addedNodes;
9680 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9681 eIt = elemSet2->begin();
9682 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9683 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9684 while ( nodeIt->more() ) { // loop on free face nodes
9685 const SMDS_MeshNode* n =
9686 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9687 if ( addedNodes.insert( n ).second )
9688 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9691 aBC /= addedNodes.size();
9692 double minDist = DBL_MAX;
9693 fIt = freeFaceList.begin();
9694 while ( fIt != freeFaceList.end() ) { // loop on free faces
9696 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9697 while ( nodeIt->more() ) { // loop on free face nodes
9698 const SMDS_MeshNode* n =
9699 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9700 gp_XYZ p( n->X(),n->Y(),n->Z() );
9701 dist += ( aBC - p ).SquareModulus();
9703 if ( dist < minDist ) {
9705 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9708 fIt = freeFaceList.erase( fIt++ );
9711 } // choose one of several free faces of a volume
9713 if ( freeFaceList.size() == 1 ) {
9714 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9715 faceSet->insert( aFreeFace );
9716 // complete a node set with nodes of a found free face
9717 // for ( iNode = 0; iNode < ; iNode++ )
9718 // nodeSet->insert( fNodes[ iNode ] );
9721 } // loop on volumes of a side
9723 // // complete a set of faces if new nodes in a nodeSet appeared
9724 // // ----------------------------------------------------------
9725 // if ( nodeSetSize != nodeSet->size() ) {
9726 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9727 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9728 // while ( fIt->more() ) { // loop on faces sharing a node
9729 // const SMDS_MeshElement* f = fIt->next();
9730 // if ( faceSet->find( f ) == faceSet->end() ) {
9731 // // check if all nodes are in nodeSet and
9732 // // complete setOfFaceNodeSet if they are
9733 // set <const SMDS_MeshNode*> faceNodeSet;
9734 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9735 // bool allInSet = true;
9736 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9737 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9738 // if ( nodeSet->find( n ) == nodeSet->end() )
9739 // allInSet = false;
9741 // faceNodeSet.insert( n );
9743 // if ( allInSet ) {
9744 // faceSet->insert( f );
9745 // setOfFaceNodeSet.insert( faceNodeSet );
9751 } // Create temporary faces, if there are volumes given
9754 if ( faceSet1.size() != faceSet2.size() ) {
9755 // delete temporary faces: they are in reverseElements of actual nodes
9756 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9757 // while ( tmpFaceIt->more() )
9758 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9759 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9760 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9761 // aMesh->RemoveElement(*tmpFaceIt);
9762 MESSAGE("Diff nb of faces");
9763 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9766 // ============================================================
9767 // 2. Find nodes to merge:
9768 // bind a node to remove to a node to put instead
9769 // ============================================================
9771 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9772 if ( theFirstNode1 != theFirstNode2 )
9773 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9774 if ( theSecondNode1 != theSecondNode2 )
9775 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9777 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9778 set< long > linkIdSet; // links to process
9779 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9781 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9782 list< NLink > linkList[2];
9783 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9784 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9785 // loop on links in linkList; find faces by links and append links
9786 // of the found faces to linkList
9787 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9788 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9789 NLink link[] = { *linkIt[0], *linkIt[1] };
9790 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9791 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9794 // by links, find faces in the face sets,
9795 // and find indices of link nodes in the found faces;
9796 // in a face set, there is only one or no face sharing a link
9797 // ---------------------------------------------------------------
9799 const SMDS_MeshElement* face[] = { 0, 0 };
9800 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9801 vector<const SMDS_MeshNode*> fnodes1(9);
9802 vector<const SMDS_MeshNode*> fnodes2(9);
9803 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9804 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9805 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9806 int iLinkNode[2][2];
9807 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9808 const SMDS_MeshNode* n1 = link[iSide].first;
9809 const SMDS_MeshNode* n2 = link[iSide].second;
9810 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9811 set< const SMDS_MeshElement* > fMap;
9812 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9813 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9814 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9815 while ( fIt->more() ) { // loop on faces sharing a node
9816 const SMDS_MeshElement* f = fIt->next();
9817 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9818 ! fMap.insert( f ).second ) // f encounters twice
9820 if ( face[ iSide ] ) {
9821 MESSAGE( "2 faces per link " );
9822 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9826 faceSet->erase( f );
9827 // get face nodes and find ones of a link
9832 fnodes1.resize(f->NbNodes()+1);
9833 notLinkNodes1.resize(f->NbNodes()-2);
9836 fnodes2.resize(f->NbNodes()+1);
9837 notLinkNodes2.resize(f->NbNodes()-2);
9840 if(!f->IsQuadratic()) {
9841 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9842 while ( nIt->more() ) {
9843 const SMDS_MeshNode* n =
9844 static_cast<const SMDS_MeshNode*>( nIt->next() );
9846 iLinkNode[ iSide ][ 0 ] = iNode;
9848 else if ( n == n2 ) {
9849 iLinkNode[ iSide ][ 1 ] = iNode;
9851 //else if ( notLinkNodes[ iSide ][ 0 ] )
9852 // notLinkNodes[ iSide ][ 1 ] = n;
9854 // notLinkNodes[ iSide ][ 0 ] = n;
9858 notLinkNodes1[nbl] = n;
9859 //notLinkNodes1.push_back(n);
9861 notLinkNodes2[nbl] = n;
9862 //notLinkNodes2.push_back(n);
9864 //faceNodes[ iSide ][ iNode++ ] = n;
9866 fnodes1[iNode++] = n;
9869 fnodes2[iNode++] = n;
9873 else { // f->IsQuadratic()
9874 const SMDS_VtkFace* F =
9875 dynamic_cast<const SMDS_VtkFace*>(f);
9876 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9877 // use special nodes iterator
9878 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9879 while ( anIter->more() ) {
9880 const SMDS_MeshNode* n =
9881 static_cast<const SMDS_MeshNode*>( anIter->next() );
9883 iLinkNode[ iSide ][ 0 ] = iNode;
9885 else if ( n == n2 ) {
9886 iLinkNode[ iSide ][ 1 ] = iNode;
9891 notLinkNodes1[nbl] = n;
9894 notLinkNodes2[nbl] = n;
9898 fnodes1[iNode++] = n;
9901 fnodes2[iNode++] = n;
9905 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9907 fnodes1[iNode] = fnodes1[0];
9910 fnodes2[iNode] = fnodes1[0];
9917 // check similarity of elements of the sides
9918 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9919 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9920 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9921 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9924 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9926 break; // do not return because it s necessary to remove tmp faces
9929 // set nodes to merge
9930 // -------------------
9932 if ( face[0] && face[1] ) {
9933 int nbNodes = face[0]->NbNodes();
9934 if ( nbNodes != face[1]->NbNodes() ) {
9935 MESSAGE("Diff nb of face nodes");
9936 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9937 break; // do not return because it s necessary to remove tmp faces
9939 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9940 if ( nbNodes == 3 ) {
9941 //nReplaceMap.insert( TNodeNodeMap::value_type
9942 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9943 nReplaceMap.insert( TNodeNodeMap::value_type
9944 ( notLinkNodes1[0], notLinkNodes2[0] ));
9947 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9948 // analyse link orientation in faces
9949 int i1 = iLinkNode[ iSide ][ 0 ];
9950 int i2 = iLinkNode[ iSide ][ 1 ];
9951 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9952 // if notLinkNodes are the first and the last ones, then
9953 // their order does not correspond to the link orientation
9954 if (( i1 == 1 && i2 == 2 ) ||
9955 ( i1 == 2 && i2 == 1 ))
9956 reverse[ iSide ] = !reverse[ iSide ];
9958 if ( reverse[0] == reverse[1] ) {
9959 //nReplaceMap.insert( TNodeNodeMap::value_type
9960 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9961 //nReplaceMap.insert( TNodeNodeMap::value_type
9962 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9963 for(int nn=0; nn<nbNodes-2; nn++) {
9964 nReplaceMap.insert( TNodeNodeMap::value_type
9965 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9969 //nReplaceMap.insert( TNodeNodeMap::value_type
9970 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9971 //nReplaceMap.insert( TNodeNodeMap::value_type
9972 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9973 for(int nn=0; nn<nbNodes-2; nn++) {
9974 nReplaceMap.insert( TNodeNodeMap::value_type
9975 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9980 // add other links of the faces to linkList
9981 // -----------------------------------------
9983 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9984 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9985 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9986 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9987 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9988 if ( !iter_isnew.second ) { // already in a set: no need to process
9989 linkIdSet.erase( iter_isnew.first );
9991 else // new in set == encountered for the first time: add
9993 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9994 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9995 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9996 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9997 linkList[0].push_back ( NLink( n1, n2 ));
9998 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10002 } // loop on link lists
10004 if ( aResult == SEW_OK &&
10005 ( linkIt[0] != linkList[0].end() ||
10006 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10007 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10008 " " << (faceSetPtr[1]->empty()));
10009 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10012 // ====================================================================
10013 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10014 // ====================================================================
10016 // delete temporary faces: they are in reverseElements of actual nodes
10017 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10018 // while ( tmpFaceIt->more() )
10019 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10020 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10021 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10022 // aMesh->RemoveElement(*tmpFaceIt);
10024 if ( aResult != SEW_OK)
10027 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10028 // loop on nodes replacement map
10029 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10030 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10031 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10032 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10033 nodeIDsToRemove.push_back( nToRemove->GetID() );
10034 // loop on elements sharing nToRemove
10035 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10036 while ( invElemIt->more() ) {
10037 const SMDS_MeshElement* e = invElemIt->next();
10038 // get a new suite of nodes: make replacement
10039 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10040 vector< const SMDS_MeshNode*> nodes( nbNodes );
10041 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10042 while ( nIt->more() ) {
10043 const SMDS_MeshNode* n =
10044 static_cast<const SMDS_MeshNode*>( nIt->next() );
10045 nnIt = nReplaceMap.find( n );
10046 if ( nnIt != nReplaceMap.end() ) {
10048 n = (*nnIt).second;
10052 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10053 // elemIDsToRemove.push_back( e->GetID() );
10057 SMDSAbs_ElementType etyp = e->GetType();
10058 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10061 myLastCreatedElems.Append(newElem);
10062 AddToSameGroups(newElem, e, aMesh);
10063 int aShapeId = e->getshapeId();
10066 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10069 aMesh->RemoveElement(e);
10074 Remove( nodeIDsToRemove, true );
10079 //================================================================================
10081 * \brief Find corresponding nodes in two sets of faces
10082 * \param theSide1 - first face set
10083 * \param theSide2 - second first face
10084 * \param theFirstNode1 - a boundary node of set 1
10085 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10086 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10087 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10088 * \param nReplaceMap - output map of corresponding nodes
10089 * \retval bool - is a success or not
10091 //================================================================================
10094 //#define DEBUG_MATCHING_NODES
10097 SMESH_MeshEditor::Sew_Error
10098 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10099 set<const SMDS_MeshElement*>& theSide2,
10100 const SMDS_MeshNode* theFirstNode1,
10101 const SMDS_MeshNode* theFirstNode2,
10102 const SMDS_MeshNode* theSecondNode1,
10103 const SMDS_MeshNode* theSecondNode2,
10104 TNodeNodeMap & nReplaceMap)
10106 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10108 nReplaceMap.clear();
10109 if ( theFirstNode1 != theFirstNode2 )
10110 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10111 if ( theSecondNode1 != theSecondNode2 )
10112 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10114 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10115 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10117 list< NLink > linkList[2];
10118 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10119 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10121 // loop on links in linkList; find faces by links and append links
10122 // of the found faces to linkList
10123 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10124 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10125 NLink link[] = { *linkIt[0], *linkIt[1] };
10126 if ( linkSet.find( link[0] ) == linkSet.end() )
10129 // by links, find faces in the face sets,
10130 // and find indices of link nodes in the found faces;
10131 // in a face set, there is only one or no face sharing a link
10132 // ---------------------------------------------------------------
10134 const SMDS_MeshElement* face[] = { 0, 0 };
10135 list<const SMDS_MeshNode*> notLinkNodes[2];
10136 //bool reverse[] = { false, false }; // order of notLinkNodes
10138 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10140 const SMDS_MeshNode* n1 = link[iSide].first;
10141 const SMDS_MeshNode* n2 = link[iSide].second;
10142 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10143 set< const SMDS_MeshElement* > facesOfNode1;
10144 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10146 // during a loop of the first node, we find all faces around n1,
10147 // during a loop of the second node, we find one face sharing both n1 and n2
10148 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10149 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10150 while ( fIt->more() ) { // loop on faces sharing a node
10151 const SMDS_MeshElement* f = fIt->next();
10152 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10153 ! facesOfNode1.insert( f ).second ) // f encounters twice
10155 if ( face[ iSide ] ) {
10156 MESSAGE( "2 faces per link " );
10157 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10160 faceSet->erase( f );
10162 // get not link nodes
10163 int nbN = f->NbNodes();
10164 if ( f->IsQuadratic() )
10166 nbNodes[ iSide ] = nbN;
10167 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10168 int i1 = f->GetNodeIndex( n1 );
10169 int i2 = f->GetNodeIndex( n2 );
10170 int iEnd = nbN, iBeg = -1, iDelta = 1;
10171 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10173 std::swap( iEnd, iBeg ); iDelta = -1;
10178 if ( i == iEnd ) i = iBeg + iDelta;
10179 if ( i == i1 ) break;
10180 nodes.push_back ( f->GetNode( i ) );
10186 // check similarity of elements of the sides
10187 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10188 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10189 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10190 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10193 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10197 // set nodes to merge
10198 // -------------------
10200 if ( face[0] && face[1] ) {
10201 if ( nbNodes[0] != nbNodes[1] ) {
10202 MESSAGE("Diff nb of face nodes");
10203 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10205 #ifdef DEBUG_MATCHING_NODES
10206 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10207 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10208 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10210 int nbN = nbNodes[0];
10212 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10213 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10214 for ( int i = 0 ; i < nbN - 2; ++i ) {
10215 #ifdef DEBUG_MATCHING_NODES
10216 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10218 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10222 // add other links of the face 1 to linkList
10223 // -----------------------------------------
10225 const SMDS_MeshElement* f0 = face[0];
10226 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10227 for ( int i = 0; i < nbN; i++ )
10229 const SMDS_MeshNode* n2 = f0->GetNode( i );
10230 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10231 linkSet.insert( SMESH_TLink( n1, n2 ));
10232 if ( !iter_isnew.second ) { // already in a set: no need to process
10233 linkSet.erase( iter_isnew.first );
10235 else // new in set == encountered for the first time: add
10237 #ifdef DEBUG_MATCHING_NODES
10238 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10239 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10241 linkList[0].push_back ( NLink( n1, n2 ));
10242 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10247 } // loop on link lists
10252 //================================================================================
10254 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10255 \param theElems - the list of elements (edges or faces) to be replicated
10256 The nodes for duplication could be found from these elements
10257 \param theNodesNot - list of nodes to NOT replicate
10258 \param theAffectedElems - the list of elements (cells and edges) to which the
10259 replicated nodes should be associated to.
10260 \return TRUE if operation has been completed successfully, FALSE otherwise
10262 //================================================================================
10264 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10265 const TIDSortedElemSet& theNodesNot,
10266 const TIDSortedElemSet& theAffectedElems )
10268 myLastCreatedElems.Clear();
10269 myLastCreatedNodes.Clear();
10271 if ( theElems.size() == 0 )
10274 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10279 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10280 // duplicate elements and nodes
10281 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10282 // replce nodes by duplications
10283 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10287 //================================================================================
10289 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10290 \param theMeshDS - mesh instance
10291 \param theElems - the elements replicated or modified (nodes should be changed)
10292 \param theNodesNot - nodes to NOT replicate
10293 \param theNodeNodeMap - relation of old node to new created node
10294 \param theIsDoubleElem - flag os to replicate element or modify
10295 \return TRUE if operation has been completed successfully, FALSE otherwise
10297 //================================================================================
10299 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10300 const TIDSortedElemSet& theElems,
10301 const TIDSortedElemSet& theNodesNot,
10302 std::map< const SMDS_MeshNode*,
10303 const SMDS_MeshNode* >& theNodeNodeMap,
10304 const bool theIsDoubleElem )
10306 MESSAGE("doubleNodes");
10307 // iterate on through element and duplicate them (by nodes duplication)
10309 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10310 for ( ; elemItr != theElems.end(); ++elemItr )
10312 const SMDS_MeshElement* anElem = *elemItr;
10316 bool isDuplicate = false;
10317 // duplicate nodes to duplicate element
10318 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10319 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10321 while ( anIter->more() )
10324 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10325 SMDS_MeshNode* aNewNode = aCurrNode;
10326 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10327 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10328 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10331 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10332 theNodeNodeMap[ aCurrNode ] = aNewNode;
10333 myLastCreatedNodes.Append( aNewNode );
10335 isDuplicate |= (aCurrNode != aNewNode);
10336 newNodes[ ind++ ] = aNewNode;
10338 if ( !isDuplicate )
10341 if ( theIsDoubleElem )
10342 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10345 MESSAGE("ChangeElementNodes");
10346 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10353 //================================================================================
10355 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10356 \param theNodes - identifiers of nodes to be doubled
10357 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10358 nodes. If list of element identifiers is empty then nodes are doubled but
10359 they not assigned to elements
10360 \return TRUE if operation has been completed successfully, FALSE otherwise
10362 //================================================================================
10364 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10365 const std::list< int >& theListOfModifiedElems )
10367 MESSAGE("DoubleNodes");
10368 myLastCreatedElems.Clear();
10369 myLastCreatedNodes.Clear();
10371 if ( theListOfNodes.size() == 0 )
10374 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10378 // iterate through nodes and duplicate them
10380 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10382 std::list< int >::const_iterator aNodeIter;
10383 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10385 int aCurr = *aNodeIter;
10386 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10392 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10395 anOldNodeToNewNode[ aNode ] = aNewNode;
10396 myLastCreatedNodes.Append( aNewNode );
10400 // Create map of new nodes for modified elements
10402 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10404 std::list< int >::const_iterator anElemIter;
10405 for ( anElemIter = theListOfModifiedElems.begin();
10406 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10408 int aCurr = *anElemIter;
10409 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10413 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10415 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10417 while ( anIter->more() )
10419 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10420 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10422 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10423 aNodeArr[ ind++ ] = aNewNode;
10426 aNodeArr[ ind++ ] = aCurrNode;
10428 anElemToNodes[ anElem ] = aNodeArr;
10431 // Change nodes of elements
10433 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10434 anElemToNodesIter = anElemToNodes.begin();
10435 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10437 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10438 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10441 MESSAGE("ChangeElementNodes");
10442 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10451 //================================================================================
10453 \brief Check if element located inside shape
10454 \return TRUE if IN or ON shape, FALSE otherwise
10456 //================================================================================
10458 template<class Classifier>
10459 bool isInside(const SMDS_MeshElement* theElem,
10460 Classifier& theClassifier,
10461 const double theTol)
10463 gp_XYZ centerXYZ (0, 0, 0);
10464 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10465 while (aNodeItr->more())
10466 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10468 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10469 theClassifier.Perform(aPnt, theTol);
10470 TopAbs_State aState = theClassifier.State();
10471 return (aState == TopAbs_IN || aState == TopAbs_ON );
10474 //================================================================================
10476 * \brief Classifier of the 3D point on the TopoDS_Face
10477 * with interaface suitable for isInside()
10479 //================================================================================
10481 struct _FaceClassifier
10483 Extrema_ExtPS _extremum;
10484 BRepAdaptor_Surface _surface;
10485 TopAbs_State _state;
10487 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10489 _extremum.Initialize( _surface,
10490 _surface.FirstUParameter(), _surface.LastUParameter(),
10491 _surface.FirstVParameter(), _surface.LastVParameter(),
10492 _surface.Tolerance(), _surface.Tolerance() );
10494 void Perform(const gp_Pnt& aPnt, double theTol)
10496 _state = TopAbs_OUT;
10497 _extremum.Perform(aPnt);
10498 if ( _extremum.IsDone() )
10499 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10500 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10502 TopAbs_State State() const
10509 //================================================================================
10511 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10512 \param theElems - group of of elements (edges or faces) to be replicated
10513 \param theNodesNot - group of nodes not to replicate
10514 \param theShape - shape to detect affected elements (element which geometric center
10515 located on or inside shape).
10516 The replicated nodes should be associated to affected elements.
10517 \return TRUE if operation has been completed successfully, FALSE otherwise
10519 //================================================================================
10521 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10522 const TIDSortedElemSet& theNodesNot,
10523 const TopoDS_Shape& theShape )
10525 if ( theShape.IsNull() )
10528 const double aTol = Precision::Confusion();
10529 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10530 auto_ptr<_FaceClassifier> aFaceClassifier;
10531 if ( theShape.ShapeType() == TopAbs_SOLID )
10533 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10534 bsc3d->PerformInfinitePoint(aTol);
10536 else if (theShape.ShapeType() == TopAbs_FACE )
10538 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10541 // iterates on indicated elements and get elements by back references from their nodes
10542 TIDSortedElemSet anAffected;
10543 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10544 for ( ; elemItr != theElems.end(); ++elemItr )
10546 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10550 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10551 while ( nodeItr->more() )
10553 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10554 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10556 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10557 while ( backElemItr->more() )
10559 const SMDS_MeshElement* curElem = backElemItr->next();
10560 if ( curElem && theElems.find(curElem) == theElems.end() &&
10562 isInside( curElem, *bsc3d, aTol ) :
10563 isInside( curElem, *aFaceClassifier, aTol )))
10564 anAffected.insert( curElem );
10568 return DoubleNodes( theElems, theNodesNot, anAffected );
10572 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10573 * The list of groups must describe a partition of the mesh volumes.
10574 * The nodes of the internal faces at the boundaries of the groups are doubled.
10575 * In option, the internal faces are replaced by flat elements.
10576 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10577 * @param theElems - list of groups of volumes, where a group of volume is a set of
10578 * SMDS_MeshElements sorted by Id.
10579 * @param createJointElems - if TRUE, create the elements
10580 * @return TRUE if operation has been completed successfully, FALSE otherwise
10582 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10583 bool createJointElems)
10585 MESSAGE("------------------------------------------------------");
10586 MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10587 MESSAGE("------------------------------------------------------");
10589 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10590 meshDS->BuildDownWardConnectivity(false);
10592 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10594 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10595 // build the list of nodes shared by 2 or more domains, with their domain indexes
10597 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10598 std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
10599 faceDomains.clear();
10600 nodeDomains.clear();
10601 std::map<int,int> emptyMap;
10604 for (int idom = 0; idom < theElems.size(); idom++)
10607 // --- build a map (face to duplicate --> volume to modify)
10608 // with all the faces shared by 2 domains (group of elements)
10609 // and corresponding volume of this domain, for each shared face.
10610 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10612 const TIDSortedElemSet& domain = theElems[idom];
10613 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10614 for (; elemItr != domain.end(); ++elemItr)
10616 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10619 int vtkId = anElem->getVtkId();
10620 int neighborsVtkIds[NBMAXNEIGHBORS];
10621 int downIds[NBMAXNEIGHBORS];
10622 unsigned char downTypes[NBMAXNEIGHBORS];
10623 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10624 for (int n = 0; n < nbNeighbors; n++)
10626 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10627 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10628 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10630 DownIdType face(downIds[n], downTypes[n]);
10631 if (!faceDomains.count(face))
10632 faceDomains[face] = emptyMap; // create an empty entry for face
10633 if (!faceDomains[face].count(idom))
10635 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10642 MESSAGE("Number of shared faces " << faceDomains.size());
10644 // --- for each shared face, get the nodes
10645 // for each node, for each domain of the face, create a clone of the node
10647 std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10648 for( ; itface != faceDomains.end();++itface )
10650 DownIdType face = itface->first;
10651 std::map<int,int> domvol = itface->second;
10652 std::set<int> oldNodes;
10654 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10655 std::set<int>::iterator itn = oldNodes.begin();
10656 for (;itn != oldNodes.end(); ++itn)
10659 if (!nodeDomains.count(oldId))
10660 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10661 std::map<int,int>::iterator itdom = domvol.begin();
10662 for(; itdom != domvol.end(); ++itdom)
10664 int idom = itdom->first;
10665 if ( nodeDomains[oldId].empty() )
10666 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10669 double *coords = grid->GetPoint(oldId);
10670 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10671 int newId = newNode->getVtkId();
10672 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10678 // --- iterate on shared faces (volumes to modify, face to extrude)
10679 // get node id's of the face (id SMDS = id VTK)
10680 // create flat element with old and new nodes if requested
10682 if (createJointElems)
10684 itface = faceDomains.begin();
10685 for( ; itface != faceDomains.end();++itface )
10687 DownIdType face = itface->first;
10688 std::set<int> oldNodes;
10689 std::set<int>::iterator itn;
10691 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10692 std::map<int,int> localClonedNodeIds;
10694 std::map<int,int> domvol = itface->second;
10695 std::map<int,int>::iterator itdom = domvol.begin();
10696 int dom1 = itdom->first;
10697 int vtkVolId = itdom->second;
10699 int dom2 = itdom->first;
10701 localClonedNodeIds.clear();
10702 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10706 if (nodeDomains[oldId].count(dom1))
10707 refid = nodeDomains[oldId][dom1];
10709 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10711 if (nodeDomains[oldId].count(dom2))
10712 newid = nodeDomains[oldId][dom2];
10714 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10715 localClonedNodeIds[oldId] = newid;
10717 meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10721 // --- iterate on shared faces (volumes to modify, face to extrude)
10722 // get node id's of the face
10723 // replace old nodes by new nodes in volumes, and update inverse connectivity
10725 itface = faceDomains.begin();
10726 for( ; itface != faceDomains.end();++itface )
10728 DownIdType face = itface->first;
10729 std::set<int> oldNodes;
10730 std::set<int>::iterator itn;
10732 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10733 std::map<int,int> localClonedNodeIds;
10735 std::map<int,int> domvol = itface->second;
10736 std::map<int,int>::iterator itdom = domvol.begin();
10737 for(; itdom != domvol.end(); ++itdom)
10739 int idom = itdom->first;
10740 int vtkVolId = itdom->second;
10741 localClonedNodeIds.clear();
10742 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10745 if (nodeDomains[oldId].count(idom))
10746 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10748 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10751 grid->BuildLinks();
10753 // TODO replace also old nodes by new nodes in faces and edges
10759 //================================================================================
10761 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10762 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10763 * \return TRUE if operation has been completed successfully, FALSE otherwise
10765 //================================================================================
10767 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10769 // iterates on volume elements and detect all free faces on them
10770 SMESHDS_Mesh* aMesh = GetMeshDS();
10773 //bool res = false;
10774 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10775 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10778 const SMDS_MeshVolume* volume = vIt->next();
10779 SMDS_VolumeTool vTool( volume );
10780 vTool.SetExternalNormal();
10781 const bool isPoly = volume->IsPoly();
10782 const bool isQuad = volume->IsQuadratic();
10783 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10785 if (!vTool.IsFreeFace(iface))
10788 vector<const SMDS_MeshNode *> nodes;
10789 int nbFaceNodes = vTool.NbFaceNodes(iface);
10790 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10792 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10793 nodes.push_back(faceNodes[inode]);
10795 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10796 nodes.push_back(faceNodes[inode]);
10798 // add new face based on volume nodes
10799 if (aMesh->FindFace( nodes ) ) {
10801 continue; // face already exsist
10803 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10807 return ( nbFree==(nbExisted+nbCreated) );
10812 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10814 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10816 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10819 //================================================================================
10821 * \brief Creates missing boundary elements
10822 * \param elements - elements whose boundary is to be checked
10823 * \param dimension - defines type of boundary elements to create
10824 * \param group - a group to store created boundary elements in
10825 * \param targetMesh - a mesh to store created boundary elements in
10826 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10827 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10828 * boundary elements will be copied into the targetMesh
10830 //================================================================================
10832 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10833 Bnd_Dimension dimension,
10834 SMESH_Group* group/*=0*/,
10835 SMESH_Mesh* targetMesh/*=0*/,
10836 bool toCopyElements/*=false*/,
10837 bool toCopyExistingBondary/*=false*/)
10839 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10840 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10841 // hope that all elements are of the same type, do not check them all
10842 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10843 throw SALOME_Exception(LOCALIZED("wrong element type"));
10846 toCopyElements = toCopyExistingBondary = false;
10848 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10849 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10851 SMDS_VolumeTool vTool;
10852 TIDSortedElemSet emptySet, avoidSet;
10855 typedef vector<const SMDS_MeshNode*> TConnectivity;
10857 SMDS_ElemIteratorPtr eIt;
10858 if (elements.empty())
10859 eIt = aMesh->elementsIterator(elemType);
10861 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10863 while (eIt->more())
10865 const SMDS_MeshElement* elem = eIt->next();
10866 const int iQuad = elem->IsQuadratic();
10868 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10869 vector<const SMDS_MeshElement*> presentBndElems;
10870 vector<TConnectivity> missingBndElems;
10871 TConnectivity nodes;
10872 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10874 vTool.SetExternalNormal();
10875 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10877 if (!vTool.IsFreeFace(iface))
10879 int nbFaceNodes = vTool.NbFaceNodes(iface);
10880 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10881 if ( missType == SMDSAbs_Edge ) // boundary edges
10883 nodes.resize( 2+iQuad );
10884 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10886 for ( int j = 0; j < nodes.size(); ++j )
10888 if ( const SMDS_MeshElement* edge =
10889 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10890 presentBndElems.push_back( edge );
10892 missingBndElems.push_back( nodes );
10895 else // boundary face
10898 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10899 nodes.push_back( nn[inode] );
10901 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10902 nodes.push_back( nn[inode] );
10904 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10905 presentBndElems.push_back( f );
10907 missingBndElems.push_back( nodes );
10911 else // elem is a face ------------------------------------------
10913 avoidSet.clear(), avoidSet.insert( elem );
10914 int nbNodes = elem->NbCornerNodes();
10915 nodes.resize( 2 /*+ iQuad*/);
10916 for ( int i = 0; i < nbNodes; i++ )
10918 nodes[0] = elem->GetNode(i);
10919 nodes[1] = elem->GetNode((i+1)%nbNodes);
10920 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10921 continue; // not free link
10924 //nodes[2] = elem->GetNode( i + nbNodes );
10925 if ( const SMDS_MeshElement* edge =
10926 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10927 presentBndElems.push_back( edge );
10929 missingBndElems.push_back( nodes );
10933 // 2. Add missing boundary elements
10934 if ( targetMesh != myMesh )
10935 // instead of making a map of nodes in this mesh and targetMesh,
10936 // we create nodes with same IDs. We can renumber them later, if needed
10937 for ( int i = 0; i < missingBndElems.size(); ++i )
10939 TConnectivity& srcNodes = missingBndElems[i];
10940 TConnectivity nodes( srcNodes.size() );
10941 for ( inode = 0; inode < nodes.size(); ++inode )
10942 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10943 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10946 for ( int i = 0; i < missingBndElems.size(); ++i )
10948 TConnectivity& nodes = missingBndElems[i];
10949 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10952 // 3. Copy present boundary elements
10953 if ( toCopyExistingBondary )
10954 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10956 const SMDS_MeshElement* e = presentBndElems[i];
10957 TConnectivity nodes( e->NbNodes() );
10958 for ( inode = 0; inode < nodes.size(); ++inode )
10959 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10960 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10961 // leave only missing elements in tgtEditor.myLastCreatedElems
10962 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10964 } // loop on given elements
10966 // 4. Fill group with missing boundary elements
10969 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10970 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10971 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10973 tgtEditor.myLastCreatedElems.Clear();
10975 // 5. Copy given elements
10976 if ( toCopyElements )
10978 if (elements.empty())
10979 eIt = aMesh->elementsIterator(elemType);
10981 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10982 while (eIt->more())
10984 const SMDS_MeshElement* elem = eIt->next();
10985 TConnectivity nodes( elem->NbNodes() );
10986 for ( inode = 0; inode < nodes.size(); ++inode )
10987 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10988 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10990 tgtEditor.myLastCreatedElems.Clear();