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 TIDSortedElemSet orphanNode;
5351 if ( theElems.empty() ) // transform the whole mesh
5354 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5355 while ( eIt->more() ) theElems.insert( eIt->next() );
5357 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5358 while ( nIt->more() )
5360 const SMDS_MeshNode* node = nIt->next();
5361 if ( node->NbInverseElements() == 0)
5362 orphanNode.insert( node );
5366 // loop on elements to transform nodes : first orphan nodes then elems
5367 TIDSortedElemSet::iterator itElem;
5368 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5369 for (int i=0; i<2; i++)
5370 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5371 const SMDS_MeshElement* elem = *itElem;
5375 // loop on elem nodes
5376 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5377 while ( itN->more() ) {
5379 const SMDS_MeshNode* node = cast2Node( itN->next() );
5380 // check if a node has been already transformed
5381 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5382 nodeMap.insert( make_pair ( node, node ));
5383 if ( !n2n_isnew.second )
5387 coord[0] = node->X();
5388 coord[1] = node->Y();
5389 coord[2] = node->Z();
5390 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5391 if ( theTargetMesh ) {
5392 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5393 n2n_isnew.first->second = newNode;
5394 myLastCreatedNodes.Append(newNode);
5395 srcNodes.Append( node );
5397 else if ( theCopy ) {
5398 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5399 n2n_isnew.first->second = newNode;
5400 myLastCreatedNodes.Append(newNode);
5401 srcNodes.Append( node );
5404 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5405 // node position on shape becomes invalid
5406 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5407 ( SMDS_SpacePosition::originSpacePosition() );
5410 // keep inverse elements
5411 if ( !theCopy && !theTargetMesh && needReverse ) {
5412 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5413 while ( invElemIt->more() ) {
5414 const SMDS_MeshElement* iel = invElemIt->next();
5415 inverseElemSet.insert( iel );
5421 // either create new elements or reverse mirrored ones
5422 if ( !theCopy && !needReverse && !theTargetMesh )
5425 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5426 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5427 theElems.insert( *invElemIt );
5429 // replicate or reverse elements
5430 // TODO revoir ordre reverse vtk
5432 REV_TETRA = 0, // = nbNodes - 4
5433 REV_PYRAMID = 1, // = nbNodes - 4
5434 REV_PENTA = 2, // = nbNodes - 4
5436 REV_HEXA = 4, // = nbNodes - 4
5440 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5441 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5442 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5443 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5444 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5445 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5448 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5450 const SMDS_MeshElement* elem = *itElem;
5451 if ( !elem || elem->GetType() == SMDSAbs_Node )
5454 int nbNodes = elem->NbNodes();
5455 int elemType = elem->GetType();
5457 if (elem->IsPoly()) {
5458 // Polygon or Polyhedral Volume
5459 switch ( elemType ) {
5462 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5464 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5465 while (itN->more()) {
5466 const SMDS_MeshNode* node =
5467 static_cast<const SMDS_MeshNode*>(itN->next());
5468 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5469 if (nodeMapIt == nodeMap.end())
5470 break; // not all nodes transformed
5472 // reverse mirrored faces and volumes
5473 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5475 poly_nodes[iNode] = (*nodeMapIt).second;
5479 if ( iNode != nbNodes )
5480 continue; // not all nodes transformed
5482 if ( theTargetMesh ) {
5483 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5484 srcElems.Append( elem );
5486 else if ( theCopy ) {
5487 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5488 srcElems.Append( elem );
5491 aMesh->ChangePolygonNodes(elem, poly_nodes);
5495 case SMDSAbs_Volume:
5497 // ATTENTION: Reversing is not yet done!!!
5498 const SMDS_VtkVolume* aPolyedre =
5499 dynamic_cast<const SMDS_VtkVolume*>( elem );
5501 MESSAGE("Warning: bad volumic element");
5505 vector<const SMDS_MeshNode*> poly_nodes;
5506 vector<int> quantities;
5508 bool allTransformed = true;
5509 int nbFaces = aPolyedre->NbFaces();
5510 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5511 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5512 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5513 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5514 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5515 if (nodeMapIt == nodeMap.end()) {
5516 allTransformed = false; // not all nodes transformed
5518 poly_nodes.push_back((*nodeMapIt).second);
5521 quantities.push_back(nbFaceNodes);
5523 if ( !allTransformed )
5524 continue; // not all nodes transformed
5526 if ( theTargetMesh ) {
5527 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5528 srcElems.Append( elem );
5530 else if ( theCopy ) {
5531 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5532 srcElems.Append( elem );
5535 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5545 int* i = index[ FORWARD ];
5546 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5547 if ( elemType == SMDSAbs_Face )
5548 i = index[ REV_FACE ];
5550 i = index[ nbNodes - 4 ];
5552 if(elem->IsQuadratic()) {
5553 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5556 if(nbNodes==3) { // quadratic edge
5557 static int anIds[] = {1,0,2};
5560 else if(nbNodes==6) { // quadratic triangle
5561 static int anIds[] = {0,2,1,5,4,3};
5564 else if(nbNodes==8) { // quadratic quadrangle
5565 static int anIds[] = {0,3,2,1,7,6,5,4};
5568 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5569 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5572 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5573 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5576 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5577 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5580 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5581 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5587 // find transformed nodes
5588 vector<const SMDS_MeshNode*> nodes(nbNodes);
5590 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5591 while ( itN->more() ) {
5592 const SMDS_MeshNode* node =
5593 static_cast<const SMDS_MeshNode*>( itN->next() );
5594 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5595 if ( nodeMapIt == nodeMap.end() )
5596 break; // not all nodes transformed
5597 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5599 if ( iNode != nbNodes )
5600 continue; // not all nodes transformed
5602 if ( theTargetMesh ) {
5603 if ( SMDS_MeshElement* copy =
5604 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5605 myLastCreatedElems.Append( copy );
5606 srcElems.Append( elem );
5609 else if ( theCopy ) {
5610 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5611 srcElems.Append( elem );
5614 // reverse element as it was reversed by transformation
5616 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5620 PGroupIDs newGroupIDs;
5622 if ( theMakeGroups && theCopy ||
5623 theMakeGroups && theTargetMesh )
5624 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5630 ////=======================================================================
5631 ////function : Scale
5633 ////=======================================================================
5635 //SMESH_MeshEditor::PGroupIDs
5636 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5637 // const gp_Pnt& thePoint,
5638 // const std::list<double>& theScaleFact,
5639 // const bool theCopy,
5640 // const bool theMakeGroups,
5641 // SMESH_Mesh* theTargetMesh)
5643 // MESSAGE("Scale");
5644 // myLastCreatedElems.Clear();
5645 // myLastCreatedNodes.Clear();
5647 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5648 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5649 // SMESHDS_Mesh* aMesh = GetMeshDS();
5651 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5652 // std::list<double>::const_iterator itS = theScaleFact.begin();
5654 // if(theScaleFact.size()==1) {
5658 // if(theScaleFact.size()==2) {
5663 // if(theScaleFact.size()>2) {
5670 // // map old node to new one
5671 // TNodeNodeMap nodeMap;
5673 // // elements sharing moved nodes; those of them which have all
5674 // // nodes mirrored but are not in theElems are to be reversed
5675 // TIDSortedElemSet inverseElemSet;
5677 // // source elements for each generated one
5678 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5680 // // loop on theElems
5681 // TIDSortedElemSet::iterator itElem;
5682 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5683 // const SMDS_MeshElement* elem = *itElem;
5687 // // loop on elem nodes
5688 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5689 // while ( itN->more() ) {
5691 // // check if a node has been already transformed
5692 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5693 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5694 // nodeMap.insert( make_pair ( node, node ));
5695 // if ( !n2n_isnew.second )
5698 // //double coord[3];
5699 // //coord[0] = node->X();
5700 // //coord[1] = node->Y();
5701 // //coord[2] = node->Z();
5702 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5703 // double dx = (node->X() - thePoint.X()) * scaleX;
5704 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5705 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5706 // if ( theTargetMesh ) {
5707 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5708 // const SMDS_MeshNode * newNode =
5709 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5710 // n2n_isnew.first->second = newNode;
5711 // myLastCreatedNodes.Append(newNode);
5712 // srcNodes.Append( node );
5714 // else if ( theCopy ) {
5715 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5716 // const SMDS_MeshNode * newNode =
5717 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5718 // n2n_isnew.first->second = newNode;
5719 // myLastCreatedNodes.Append(newNode);
5720 // srcNodes.Append( node );
5723 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5724 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5725 // // node position on shape becomes invalid
5726 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5727 // ( SMDS_SpacePosition::originSpacePosition() );
5730 // // keep inverse elements
5731 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5732 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5733 // // while ( invElemIt->more() ) {
5734 // // const SMDS_MeshElement* iel = invElemIt->next();
5735 // // inverseElemSet.insert( iel );
5741 // // either create new elements or reverse mirrored ones
5742 // //if ( !theCopy && !needReverse && !theTargetMesh )
5743 // if ( !theCopy && !theTargetMesh )
5744 // return PGroupIDs();
5746 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5747 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5748 // theElems.insert( *invElemIt );
5750 // // replicate or reverse elements
5753 // REV_TETRA = 0, // = nbNodes - 4
5754 // REV_PYRAMID = 1, // = nbNodes - 4
5755 // REV_PENTA = 2, // = nbNodes - 4
5757 // REV_HEXA = 4, // = nbNodes - 4
5760 // int index[][8] = {
5761 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5762 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5763 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5764 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5765 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5766 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5769 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5771 // const SMDS_MeshElement* elem = *itElem;
5772 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5775 // int nbNodes = elem->NbNodes();
5776 // int elemType = elem->GetType();
5778 // if (elem->IsPoly()) {
5779 // // Polygon or Polyhedral Volume
5780 // switch ( elemType ) {
5781 // case SMDSAbs_Face:
5783 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5785 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5786 // while (itN->more()) {
5787 // const SMDS_MeshNode* node =
5788 // static_cast<const SMDS_MeshNode*>(itN->next());
5789 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5790 // if (nodeMapIt == nodeMap.end())
5791 // break; // not all nodes transformed
5792 // //if (needReverse) {
5793 // // // reverse mirrored faces and volumes
5794 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5796 // poly_nodes[iNode] = (*nodeMapIt).second;
5800 // if ( iNode != nbNodes )
5801 // continue; // not all nodes transformed
5803 // if ( theTargetMesh ) {
5804 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5805 // srcElems.Append( elem );
5807 // else if ( theCopy ) {
5808 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5809 // srcElems.Append( elem );
5812 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5816 // case SMDSAbs_Volume:
5818 // // ATTENTION: Reversing is not yet done!!!
5819 // const SMDS_VtkVolume* aPolyedre =
5820 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5821 // if (!aPolyedre) {
5822 // MESSAGE("Warning: bad volumic element");
5826 // vector<const SMDS_MeshNode*> poly_nodes;
5827 // vector<int> quantities;
5829 // bool allTransformed = true;
5830 // int nbFaces = aPolyedre->NbFaces();
5831 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5832 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5833 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5834 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5835 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5836 // if (nodeMapIt == nodeMap.end()) {
5837 // allTransformed = false; // not all nodes transformed
5839 // poly_nodes.push_back((*nodeMapIt).second);
5842 // quantities.push_back(nbFaceNodes);
5844 // if ( !allTransformed )
5845 // continue; // not all nodes transformed
5847 // if ( theTargetMesh ) {
5848 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5849 // srcElems.Append( elem );
5851 // else if ( theCopy ) {
5852 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5853 // srcElems.Append( elem );
5856 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5865 // // Regular elements
5866 // int* i = index[ FORWARD ];
5867 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5868 // // if ( elemType == SMDSAbs_Face )
5869 // // i = index[ REV_FACE ];
5871 // // i = index[ nbNodes - 4 ];
5873 // if(elem->IsQuadratic()) {
5874 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5876 // //if(needReverse) {
5877 // // if(nbNodes==3) { // quadratic edge
5878 // // static int anIds[] = {1,0,2};
5881 // // else if(nbNodes==6) { // quadratic triangle
5882 // // static int anIds[] = {0,2,1,5,4,3};
5885 // // else if(nbNodes==8) { // quadratic quadrangle
5886 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5889 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5890 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5893 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5894 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5897 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5898 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5901 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5902 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5908 // // find transformed nodes
5909 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5911 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5912 // while ( itN->more() ) {
5913 // const SMDS_MeshNode* node =
5914 // static_cast<const SMDS_MeshNode*>( itN->next() );
5915 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5916 // if ( nodeMapIt == nodeMap.end() )
5917 // break; // not all nodes transformed
5918 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5920 // if ( iNode != nbNodes )
5921 // continue; // not all nodes transformed
5923 // if ( theTargetMesh ) {
5924 // if ( SMDS_MeshElement* copy =
5925 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5926 // myLastCreatedElems.Append( copy );
5927 // srcElems.Append( elem );
5930 // else if ( theCopy ) {
5931 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5932 // myLastCreatedElems.Append( copy );
5933 // srcElems.Append( elem );
5937 // // reverse element as it was reversed by transformation
5938 // if ( nbNodes > 2 )
5939 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5943 // PGroupIDs newGroupIDs;
5945 // if ( theMakeGroups && theCopy ||
5946 // theMakeGroups && theTargetMesh ) {
5947 // string groupPostfix = "scaled";
5948 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5951 // return newGroupIDs;
5955 //=======================================================================
5957 * \brief Create groups of elements made during transformation
5958 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5959 * \param elemGens - elements making corresponding myLastCreatedElems
5960 * \param postfix - to append to names of new groups
5962 //=======================================================================
5964 SMESH_MeshEditor::PGroupIDs
5965 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5966 const SMESH_SequenceOfElemPtr& elemGens,
5967 const std::string& postfix,
5968 SMESH_Mesh* targetMesh)
5970 PGroupIDs newGroupIDs( new list<int> );
5971 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5973 // Sort existing groups by types and collect their names
5975 // to store an old group and a generated new one
5976 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5977 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5979 set< string > groupNames;
5981 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5982 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5983 while ( groupIt->more() ) {
5984 SMESH_Group * group = groupIt->next();
5985 if ( !group ) continue;
5986 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5987 if ( !groupDS || groupDS->IsEmpty() ) continue;
5988 groupNames.insert( group->GetName() );
5989 groupDS->SetStoreName( group->GetName() );
5990 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5995 // loop on nodes and elements
5996 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5998 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5999 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6000 if ( gens.Length() != elems.Length() )
6001 throw SALOME_Exception(LOCALIZED("invalid args"));
6003 // loop on created elements
6004 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6006 const SMDS_MeshElement* sourceElem = gens( iElem );
6007 if ( !sourceElem ) {
6008 MESSAGE("generateGroups(): NULL source element");
6011 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6012 if ( groupsOldNew.empty() ) {
6013 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6014 ++iElem; // skip all elements made by sourceElem
6017 // collect all elements made by sourceElem
6018 list< const SMDS_MeshElement* > resultElems;
6019 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6020 if ( resElem != sourceElem )
6021 resultElems.push_back( resElem );
6022 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6023 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6024 if ( resElem != sourceElem )
6025 resultElems.push_back( resElem );
6026 // do not generate element groups from node ones
6027 if ( sourceElem->GetType() == SMDSAbs_Node &&
6028 elems( iElem )->GetType() != SMDSAbs_Node )
6031 // add resultElems to groups made by ones the sourceElem belongs to
6032 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6033 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6035 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6036 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6038 SMDS_MeshGroup* & newGroup = gOldNew->second;
6039 if ( !newGroup )// create a new group
6042 string name = oldGroup->GetStoreName();
6043 if ( !targetMesh ) {
6047 while ( !groupNames.insert( name ).second ) // name exists
6053 TCollection_AsciiString nbStr(nb+1);
6054 name.resize( name.rfind('_')+1 );
6055 name += nbStr.ToCString();
6062 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6064 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6065 newGroup = & groupDS->SMDSGroup();
6066 newGroupIDs->push_back( id );
6069 // fill in a new group
6070 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6071 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6072 newGroup->Add( *resElemIt );
6075 } // loop on created elements
6076 }// loop on nodes and elements
6081 //================================================================================
6083 * \brief Return list of group of nodes close to each other within theTolerance
6084 * Search among theNodes or in the whole mesh if theNodes is empty using
6085 * an Octree algorithm
6087 //================================================================================
6089 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6090 const double theTolerance,
6091 TListOfListOfNodes & theGroupsOfNodes)
6093 myLastCreatedElems.Clear();
6094 myLastCreatedNodes.Clear();
6096 if ( theNodes.empty() )
6097 { // get all nodes in the mesh
6098 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6099 while ( nIt->more() )
6100 theNodes.insert( theNodes.end(),nIt->next());
6103 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6107 //=======================================================================
6109 * \brief Implementation of search for the node closest to point
6111 //=======================================================================
6113 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6115 //---------------------------------------------------------------------
6117 * \brief Constructor
6119 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6121 myMesh = ( SMESHDS_Mesh* ) theMesh;
6123 TIDSortedNodeSet nodes;
6125 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6126 while ( nIt->more() )
6127 nodes.insert( nodes.end(), nIt->next() );
6129 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6131 // get max size of a leaf box
6132 SMESH_OctreeNode* tree = myOctreeNode;
6133 while ( !tree->isLeaf() )
6135 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6139 myHalfLeafSize = tree->maxSize() / 2.;
6142 //---------------------------------------------------------------------
6144 * \brief Move node and update myOctreeNode accordingly
6146 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6148 myOctreeNode->UpdateByMoveNode( node, toPnt );
6149 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6152 //---------------------------------------------------------------------
6154 * \brief Do it's job
6156 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6158 map<double, const SMDS_MeshNode*> dist2Nodes;
6159 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6160 if ( !dist2Nodes.empty() )
6161 return dist2Nodes.begin()->second;
6162 list<const SMDS_MeshNode*> nodes;
6163 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6165 double minSqDist = DBL_MAX;
6166 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6168 // sort leafs by their distance from thePnt
6169 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6170 TDistTreeMap treeMap;
6171 list< SMESH_OctreeNode* > treeList;
6172 list< SMESH_OctreeNode* >::iterator trIt;
6173 treeList.push_back( myOctreeNode );
6175 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6176 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6177 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6179 SMESH_OctreeNode* tree = *trIt;
6180 if ( !tree->isLeaf() ) // put children to the queue
6182 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6183 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6184 while ( cIt->more() )
6185 treeList.push_back( cIt->next() );
6187 else if ( tree->NbNodes() ) // put a tree to the treeMap
6189 const Bnd_B3d& box = tree->getBox();
6190 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6191 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6192 if ( !it_in.second ) // not unique distance to box center
6193 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6196 // find distance after which there is no sense to check tree's
6197 double sqLimit = DBL_MAX;
6198 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6199 if ( treeMap.size() > 5 ) {
6200 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6201 const Bnd_B3d& box = closestTree->getBox();
6202 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6203 sqLimit = limit * limit;
6205 // get all nodes from trees
6206 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6207 if ( sqDist_tree->first > sqLimit )
6209 SMESH_OctreeNode* tree = sqDist_tree->second;
6210 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6213 // find closest among nodes
6214 minSqDist = DBL_MAX;
6215 const SMDS_MeshNode* closestNode = 0;
6216 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6217 for ( ; nIt != nodes.end(); ++nIt ) {
6218 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6219 if ( minSqDist > sqDist ) {
6227 //---------------------------------------------------------------------
6231 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6233 //---------------------------------------------------------------------
6235 * \brief Return the node tree
6237 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6240 SMESH_OctreeNode* myOctreeNode;
6241 SMESHDS_Mesh* myMesh;
6242 double myHalfLeafSize; // max size of a leaf box
6245 //=======================================================================
6247 * \brief Return SMESH_NodeSearcher
6249 //=======================================================================
6251 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6253 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6256 // ========================================================================
6257 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6259 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6260 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6261 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6263 //=======================================================================
6265 * \brief Octal tree of bounding boxes of elements
6267 //=======================================================================
6269 class ElementBndBoxTree : public SMESH_Octree
6273 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
6274 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6275 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6276 ~ElementBndBoxTree();
6279 ElementBndBoxTree() {}
6280 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6281 void buildChildrenData();
6282 Bnd_B3d* buildRootBox();
6284 //!< Bounding box of element
6285 struct ElementBox : public Bnd_B3d
6287 const SMDS_MeshElement* _element;
6288 int _refCount; // an ElementBox can be included in several tree branches
6289 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6291 vector< ElementBox* > _elements;
6294 //================================================================================
6296 * \brief ElementBndBoxTree creation
6298 //================================================================================
6300 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
6301 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6303 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6304 _elements.reserve( nbElems );
6306 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6307 while ( elemIt->more() )
6308 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6310 if ( _elements.size() > MaxNbElemsInLeaf )
6316 //================================================================================
6320 //================================================================================
6322 ElementBndBoxTree::~ElementBndBoxTree()
6324 for ( int i = 0; i < _elements.size(); ++i )
6325 if ( --_elements[i]->_refCount <= 0 )
6326 delete _elements[i];
6329 //================================================================================
6331 * \brief Return the maximal box
6333 //================================================================================
6335 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6337 Bnd_B3d* box = new Bnd_B3d;
6338 for ( int i = 0; i < _elements.size(); ++i )
6339 box->Add( *_elements[i] );
6343 //================================================================================
6345 * \brief Redistrubute element boxes among children
6347 //================================================================================
6349 void ElementBndBoxTree::buildChildrenData()
6351 for ( int i = 0; i < _elements.size(); ++i )
6353 for (int j = 0; j < 8; j++)
6355 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6357 _elements[i]->_refCount++;
6358 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6361 _elements[i]->_refCount--;
6365 for (int j = 0; j < 8; j++)
6367 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6368 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6369 child->myIsLeaf = true;
6371 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6372 child->_elements.resize( child->_elements.size() ); // compact
6376 //================================================================================
6378 * \brief Return elements which can include the point
6380 //================================================================================
6382 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6383 TIDSortedElemSet& foundElems)
6385 if ( level() && getBox().IsOut( point.XYZ() ))
6390 for ( int i = 0; i < _elements.size(); ++i )
6391 if ( !_elements[i]->IsOut( point.XYZ() ))
6392 foundElems.insert( _elements[i]->_element );
6396 for (int i = 0; i < 8; i++)
6397 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6401 //================================================================================
6403 * \brief Return elements which can be intersected by the line
6405 //================================================================================
6407 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6408 TIDSortedElemSet& foundElems)
6410 if ( level() && getBox().IsOut( line ))
6415 for ( int i = 0; i < _elements.size(); ++i )
6416 if ( !_elements[i]->IsOut( line ))
6417 foundElems.insert( _elements[i]->_element );
6421 for (int i = 0; i < 8; i++)
6422 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6426 //================================================================================
6428 * \brief Construct the element box
6430 //================================================================================
6432 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6436 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6437 while ( nIt->more() )
6438 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6439 Enlarge( tolerance );
6444 //=======================================================================
6446 * \brief Implementation of search for the elements by point and
6447 * of classification of point in 2D mesh
6449 //=======================================================================
6451 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6453 SMESHDS_Mesh* _mesh;
6454 ElementBndBoxTree* _ebbTree;
6455 SMESH_NodeSearcherImpl* _nodeSearcher;
6456 SMDSAbs_ElementType _elementType;
6458 bool _outerFacesFound;
6459 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6461 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6462 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6463 ~SMESH_ElementSearcherImpl()
6465 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6466 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6468 virtual int FindElementsByPoint(const gp_Pnt& point,
6469 SMDSAbs_ElementType type,
6470 vector< const SMDS_MeshElement* >& foundElements);
6471 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6473 void GetElementsNearLine( const gp_Ax1& line,
6474 SMDSAbs_ElementType type,
6475 vector< const SMDS_MeshElement* >& foundElems);
6476 double getTolerance();
6477 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6478 const double tolerance, double & param);
6479 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6480 bool isOuterBoundary(const SMDS_MeshElement* face) const
6482 return _outerFaces.empty() || _outerFaces.count(face);
6484 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6486 const SMDS_MeshElement* _face;
6488 bool _coincides; //!< the line lays in face plane
6489 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6490 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6492 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6495 TIDSortedElemSet _faces;
6496 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6497 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6501 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6503 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6504 << ", _coincides="<<i._coincides << ")";
6507 //=======================================================================
6509 * \brief define tolerance for search
6511 //=======================================================================
6513 double SMESH_ElementSearcherImpl::getTolerance()
6515 if ( _tolerance < 0 )
6517 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6520 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6522 double boxSize = _nodeSearcher->getTree()->maxSize();
6523 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6525 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6527 double boxSize = _ebbTree->maxSize();
6528 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6530 if ( _tolerance == 0 )
6532 // define tolerance by size of a most complex element
6533 int complexType = SMDSAbs_Volume;
6534 while ( complexType > SMDSAbs_All &&
6535 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6537 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6539 if ( complexType == int( SMDSAbs_Node ))
6541 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6543 if ( meshInfo.NbNodes() > 2 )
6544 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6548 SMDS_ElemIteratorPtr elemIt =
6549 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6550 const SMDS_MeshElement* elem = elemIt->next();
6551 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6552 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6553 while ( nodeIt->more() )
6555 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6556 elemSize = max( dist, elemSize );
6559 _tolerance = 1e-4 * elemSize;
6565 //================================================================================
6567 * \brief Find intersection of the line and an edge of face and return parameter on line
6569 //================================================================================
6571 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6572 const SMDS_MeshElement* face,
6579 GeomAPI_ExtremaCurveCurve anExtCC;
6580 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6582 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6583 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6585 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6586 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6587 anExtCC.Init( lineCurve, edge);
6588 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6590 Quantity_Parameter pl, pe;
6591 anExtCC.LowerDistanceParameters( pl, pe );
6593 if ( ++nbInts == 2 )
6597 if ( nbInts > 0 ) param /= nbInts;
6600 //================================================================================
6602 * \brief Find all faces belonging to the outer boundary of mesh
6604 //================================================================================
6606 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6608 if ( _outerFacesFound ) return;
6610 // Collect all outer faces by passing from one outer face to another via their links
6611 // and BTW find out if there are internal faces at all.
6613 // checked links and links where outer boundary meets internal one
6614 set< SMESH_TLink > visitedLinks, seamLinks;
6616 // links to treat with already visited faces sharing them
6617 list < TFaceLink > startLinks;
6619 // load startLinks with the first outerFace
6620 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6621 _outerFaces.insert( outerFace );
6623 TIDSortedElemSet emptySet;
6624 while ( !startLinks.empty() )
6626 const SMESH_TLink& link = startLinks.front()._link;
6627 TIDSortedElemSet& faces = startLinks.front()._faces;
6629 outerFace = *faces.begin();
6630 // find other faces sharing the link
6631 const SMDS_MeshElement* f;
6632 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6635 // select another outer face among the found
6636 const SMDS_MeshElement* outerFace2 = 0;
6637 if ( faces.size() == 2 )
6639 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6641 else if ( faces.size() > 2 )
6643 seamLinks.insert( link );
6645 // link direction within the outerFace
6646 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6647 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6648 int i1 = outerFace->GetNodeIndex( link.node1() );
6649 int i2 = outerFace->GetNodeIndex( link.node2() );
6650 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6651 if ( rev ) n1n2.Reverse();
6653 gp_XYZ ofNorm, fNorm;
6654 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6656 // direction from the link inside outerFace
6657 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6658 // sort all other faces by angle with the dirInOF
6659 map< double, const SMDS_MeshElement* > angle2Face;
6660 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6661 for ( ; face != faces.end(); ++face )
6663 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6665 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6666 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6667 if ( angle < 0 ) angle += 2*PI;
6668 angle2Face.insert( make_pair( angle, *face ));
6670 if ( !angle2Face.empty() )
6671 outerFace2 = angle2Face.begin()->second;
6674 // store the found outer face and add its links to continue seaching from
6677 _outerFaces.insert( outerFace );
6678 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6679 for ( int i = 0; i < nbNodes; ++i )
6681 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6682 if ( visitedLinks.insert( link2 ).second )
6683 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6686 startLinks.pop_front();
6688 _outerFacesFound = true;
6690 if ( !seamLinks.empty() )
6692 // There are internal boundaries touching the outher one,
6693 // find all faces of internal boundaries in order to find
6694 // faces of boundaries of holes, if any.
6699 _outerFaces.clear();
6703 //=======================================================================
6705 * \brief Find elements of given type where the given point is IN or ON.
6706 * Returns nb of found elements and elements them-selves.
6708 * 'ALL' type means elements of any type excluding nodes and 0D elements
6710 //=======================================================================
6712 int SMESH_ElementSearcherImpl::
6713 FindElementsByPoint(const gp_Pnt& point,
6714 SMDSAbs_ElementType type,
6715 vector< const SMDS_MeshElement* >& foundElements)
6717 foundElements.clear();
6719 double tolerance = getTolerance();
6721 // =================================================================================
6722 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6724 if ( !_nodeSearcher )
6725 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6727 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6728 if ( !closeNode ) return foundElements.size();
6730 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6731 return foundElements.size(); // to far from any node
6733 if ( type == SMDSAbs_Node )
6735 foundElements.push_back( closeNode );
6739 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6740 while ( elemIt->more() )
6741 foundElements.push_back( elemIt->next() );
6744 // =================================================================================
6745 else // elements more complex than 0D
6747 if ( !_ebbTree || _elementType != type )
6749 if ( _ebbTree ) delete _ebbTree;
6750 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6752 TIDSortedElemSet suspectElems;
6753 _ebbTree->getElementsNearPoint( point, suspectElems );
6754 TIDSortedElemSet::iterator elem = suspectElems.begin();
6755 for ( ; elem != suspectElems.end(); ++elem )
6756 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6757 foundElements.push_back( *elem );
6759 return foundElements.size();
6762 //================================================================================
6764 * \brief Classify the given point in the closed 2D mesh
6766 //================================================================================
6768 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6770 double tolerance = getTolerance();
6771 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6773 if ( _ebbTree ) delete _ebbTree;
6774 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6776 // Algo: analyse transition of a line starting at the point through mesh boundary;
6777 // try three lines parallel to axis of the coordinate system and perform rough
6778 // analysis. If solution is not clear perform thorough analysis.
6780 const int nbAxes = 3;
6781 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6782 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6783 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6784 multimap< int, int > nbInt2Axis; // to find the simplest case
6785 for ( int axis = 0; axis < nbAxes; ++axis )
6787 gp_Ax1 lineAxis( point, axisDir[axis]);
6788 gp_Lin line ( lineAxis );
6790 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6791 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6793 // Intersect faces with the line
6795 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6796 TIDSortedElemSet::iterator face = suspectFaces.begin();
6797 for ( ; face != suspectFaces.end(); ++face )
6801 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6802 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6804 // perform intersection
6805 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6806 if ( !intersection.IsDone() )
6808 if ( intersection.IsInQuadric() )
6810 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6812 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6814 gp_Pnt intersectionPoint = intersection.Point(1);
6815 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6816 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6819 // Analyse intersections roughly
6821 int nbInter = u2inters.size();
6825 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6826 if ( nbInter == 1 ) // not closed mesh
6827 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6829 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6832 if ( (f<0) == (l<0) )
6835 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6836 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6837 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6840 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6842 if ( _outerFacesFound ) break; // pass to thorough analysis
6844 } // three attempts - loop on CS axes
6846 // Analyse intersections thoroughly.
6847 // We make two loops maximum, on the first one we only exclude touching intersections,
6848 // on the second, if situation is still unclear, we gather and use information on
6849 // position of faces (internal or outer). If faces position is already gathered,
6850 // we make the second loop right away.
6852 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6854 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6855 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6857 int axis = nb_axis->second;
6858 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6860 gp_Ax1 lineAxis( point, axisDir[axis]);
6861 gp_Lin line ( lineAxis );
6863 // add tangent intersections to u2inters
6865 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6866 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6867 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6868 u2inters.insert(make_pair( param, *tgtInt ));
6869 tangentInters[ axis ].clear();
6871 // Count intersections before and after the point excluding touching ones.
6872 // If hasPositionInfo we count intersections of outer boundary only
6874 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6875 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6876 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6877 bool ok = ! u_int1->second._coincides;
6878 while ( ok && u_int1 != u2inters.end() )
6880 double u = u_int1->first;
6881 bool touchingInt = false;
6882 if ( ++u_int2 != u2inters.end() )
6884 // skip intersections at the same point (if the line passes through edge or node)
6886 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6892 // skip tangent intersections
6894 const SMDS_MeshElement* prevFace = u_int1->second._face;
6895 while ( ok && u_int2->second._coincides )
6897 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6903 ok = ( u_int2 != u2inters.end() );
6908 // skip intersections at the same point after tangent intersections
6911 double u2 = u_int2->first;
6913 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6919 // decide if we skipped a touching intersection
6920 if ( nbSamePnt + nbTgt > 0 )
6922 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6923 map< double, TInters >::iterator u_int = u_int1;
6924 for ( ; u_int != u_int2; ++u_int )
6926 if ( u_int->second._coincides ) continue;
6927 double dot = u_int->second._faceNorm * line.Direction();
6928 if ( dot > maxDot ) maxDot = dot;
6929 if ( dot < minDot ) minDot = dot;
6931 touchingInt = ( minDot*maxDot < 0 );
6936 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6947 u_int1 = u_int2; // to next intersection
6949 } // loop on intersections with one line
6953 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6956 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6959 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6960 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6962 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6965 if ( (f<0) == (l<0) )
6968 if ( hasPositionInfo )
6969 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6971 } // loop on intersections of the tree lines - thorough analysis
6973 if ( !hasPositionInfo )
6975 // gather info on faces position - is face in the outer boundary or not
6976 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6977 findOuterBoundary( u2inters.begin()->second._face );
6980 } // two attempts - with and w/o faces position info in the mesh
6982 return TopAbs_UNKNOWN;
6985 //=======================================================================
6987 * \brief Return elements possibly intersecting the line
6989 //=======================================================================
6991 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
6992 SMDSAbs_ElementType type,
6993 vector< const SMDS_MeshElement* >& foundElems)
6995 if ( !_ebbTree || _elementType != type )
6997 if ( _ebbTree ) delete _ebbTree;
6998 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
7000 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7001 _ebbTree->getElementsNearLine( line, suspectFaces );
7002 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7005 //=======================================================================
7007 * \brief Return SMESH_ElementSearcher
7009 //=======================================================================
7011 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7013 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7016 //=======================================================================
7018 * \brief Return true if the point is IN or ON of the element
7020 //=======================================================================
7022 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7024 if ( element->GetType() == SMDSAbs_Volume)
7026 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7029 // get ordered nodes
7031 vector< gp_XYZ > xyz;
7032 vector<const SMDS_MeshNode*> nodeList;
7034 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7035 if ( element->IsQuadratic() ) {
7036 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7037 nodeIt = f->interlacedNodesElemIterator();
7038 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7039 nodeIt = e->interlacedNodesElemIterator();
7041 while ( nodeIt->more() )
7043 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7044 xyz.push_back( TNodeXYZ(node) );
7045 nodeList.push_back(node);
7048 int i, nbNodes = element->NbNodes();
7050 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7052 // compute face normal
7053 gp_Vec faceNorm(0,0,0);
7054 xyz.push_back( xyz.front() );
7055 nodeList.push_back( nodeList.front() );
7056 for ( i = 0; i < nbNodes; ++i )
7058 gp_Vec edge1( xyz[i+1], xyz[i]);
7059 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7060 faceNorm += edge1 ^ edge2;
7062 double normSize = faceNorm.Magnitude();
7063 if ( normSize <= tol )
7065 // degenerated face: point is out if it is out of all face edges
7066 for ( i = 0; i < nbNodes; ++i )
7068 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7069 if ( !isOut( &edge, point, tol ))
7074 faceNorm /= normSize;
7076 // check if the point lays on face plane
7077 gp_Vec n2p( xyz[0], point );
7078 if ( fabs( n2p * faceNorm ) > tol )
7079 return true; // not on face plane
7081 // check if point is out of face boundary:
7082 // define it by closest transition of a ray point->infinity through face boundary
7083 // on the face plane.
7084 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7085 // to find intersections of the ray with the boundary.
7087 gp_Vec plnNorm = ray ^ faceNorm;
7088 normSize = plnNorm.Magnitude();
7089 if ( normSize <= tol ) return false; // point coincides with the first node
7090 plnNorm /= normSize;
7091 // for each node of the face, compute its signed distance to the plane
7092 vector<double> dist( nbNodes + 1);
7093 for ( i = 0; i < nbNodes; ++i )
7095 gp_Vec n2p( xyz[i], point );
7096 dist[i] = n2p * plnNorm;
7098 dist.back() = dist.front();
7099 // find the closest intersection
7101 double rClosest, distClosest = 1e100;;
7103 for ( i = 0; i < nbNodes; ++i )
7106 if ( fabs( dist[i]) < tol )
7108 else if ( fabs( dist[i+1]) < tol )
7110 else if ( dist[i] * dist[i+1] < 0 )
7111 r = dist[i] / ( dist[i] - dist[i+1] );
7113 continue; // no intersection
7114 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7115 gp_Vec p2int ( point, pInt);
7116 if ( p2int * ray > -tol ) // right half-space
7118 double intDist = p2int.SquareMagnitude();
7119 if ( intDist < distClosest )
7124 distClosest = intDist;
7129 return true; // no intesections - out
7131 // analyse transition
7132 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7133 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7134 gp_Vec p2int ( point, pClosest );
7135 bool out = (edgeNorm * p2int) < -tol;
7136 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7139 // ray pass through a face node; analyze transition through an adjacent edge
7140 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7141 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7142 gp_Vec edgeAdjacent( p1, p2 );
7143 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7144 bool out2 = (edgeNorm2 * p2int) < -tol;
7146 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7147 return covexCorner ? (out || out2) : (out && out2);
7149 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7151 // point is out of edge if it is NOT ON any straight part of edge
7152 // (we consider quadratic edge as being composed of two straight parts)
7153 for ( i = 1; i < nbNodes; ++i )
7155 gp_Vec edge( xyz[i-1], xyz[i]);
7156 gp_Vec n1p ( xyz[i-1], point);
7157 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7160 gp_Vec n2p( xyz[i], point );
7161 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7163 return false; // point is ON this part
7167 // Node or 0D element -------------------------------------------------------------------------
7169 gp_Vec n2p ( xyz[0], point );
7170 return n2p.Magnitude() <= tol;
7175 //=======================================================================
7176 //function : SimplifyFace
7178 //=======================================================================
7179 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7180 vector<const SMDS_MeshNode *>& poly_nodes,
7181 vector<int>& quantities) const
7183 int nbNodes = faceNodes.size();
7188 set<const SMDS_MeshNode*> nodeSet;
7190 // get simple seq of nodes
7191 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7192 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7193 int iSimple = 0, nbUnique = 0;
7195 simpleNodes[iSimple++] = faceNodes[0];
7197 for (int iCur = 1; iCur < nbNodes; iCur++) {
7198 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7199 simpleNodes[iSimple++] = faceNodes[iCur];
7200 if (nodeSet.insert( faceNodes[iCur] ).second)
7204 int nbSimple = iSimple;
7205 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7215 bool foundLoop = (nbSimple > nbUnique);
7218 set<const SMDS_MeshNode*> loopSet;
7219 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7220 const SMDS_MeshNode* n = simpleNodes[iSimple];
7221 if (!loopSet.insert( n ).second) {
7225 int iC = 0, curLast = iSimple;
7226 for (; iC < curLast; iC++) {
7227 if (simpleNodes[iC] == n) break;
7229 int loopLen = curLast - iC;
7231 // create sub-element
7233 quantities.push_back(loopLen);
7234 for (; iC < curLast; iC++) {
7235 poly_nodes.push_back(simpleNodes[iC]);
7238 // shift the rest nodes (place from the first loop position)
7239 for (iC = curLast + 1; iC < nbSimple; iC++) {
7240 simpleNodes[iC - loopLen] = simpleNodes[iC];
7242 nbSimple -= loopLen;
7245 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7246 } // while (foundLoop)
7250 quantities.push_back(iSimple);
7251 for (int i = 0; i < iSimple; i++)
7252 poly_nodes.push_back(simpleNodes[i]);
7258 //=======================================================================
7259 //function : MergeNodes
7260 //purpose : In each group, the cdr of nodes are substituted by the first one
7262 //=======================================================================
7264 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7266 MESSAGE("MergeNodes");
7267 myLastCreatedElems.Clear();
7268 myLastCreatedNodes.Clear();
7270 SMESHDS_Mesh* aMesh = GetMeshDS();
7272 TNodeNodeMap nodeNodeMap; // node to replace - new node
7273 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7274 list< int > rmElemIds, rmNodeIds;
7276 // Fill nodeNodeMap and elems
7278 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7279 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7280 list<const SMDS_MeshNode*>& nodes = *grIt;
7281 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7282 const SMDS_MeshNode* nToKeep = *nIt;
7283 //MESSAGE("node to keep " << nToKeep->GetID());
7284 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7285 const SMDS_MeshNode* nToRemove = *nIt;
7286 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7287 if ( nToRemove != nToKeep ) {
7288 //MESSAGE(" node to remove " << nToRemove->GetID());
7289 rmNodeIds.push_back( nToRemove->GetID() );
7290 AddToSameGroups( nToKeep, nToRemove, aMesh );
7293 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7294 while ( invElemIt->more() ) {
7295 const SMDS_MeshElement* elem = invElemIt->next();
7300 // Change element nodes or remove an element
7302 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7303 for ( ; eIt != elems.end(); eIt++ ) {
7304 const SMDS_MeshElement* elem = *eIt;
7305 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7306 int nbNodes = elem->NbNodes();
7307 int aShapeId = FindShape( elem );
7309 set<const SMDS_MeshNode*> nodeSet;
7310 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7311 int iUnique = 0, iCur = 0, nbRepl = 0;
7312 vector<int> iRepl( nbNodes );
7314 // get new seq of nodes
7315 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7316 while ( itN->more() ) {
7317 const SMDS_MeshNode* n =
7318 static_cast<const SMDS_MeshNode*>( itN->next() );
7320 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7321 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7323 // BUG 0020185: begin
7325 bool stopRecur = false;
7326 set<const SMDS_MeshNode*> nodesRecur;
7327 nodesRecur.insert(n);
7328 while (!stopRecur) {
7329 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7330 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7331 n = (*nnIt_i).second;
7332 if (!nodesRecur.insert(n).second) {
7333 // error: recursive dependancy
7342 iRepl[ nbRepl++ ] = iCur;
7344 curNodes[ iCur ] = n;
7345 bool isUnique = nodeSet.insert( n ).second;
7347 uniqueNodes[ iUnique++ ] = n;
7351 // Analyse element topology after replacement
7354 int nbUniqueNodes = nodeSet.size();
7355 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7356 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7357 // Polygons and Polyhedral volumes
7358 if (elem->IsPoly()) {
7360 if (elem->GetType() == SMDSAbs_Face) {
7362 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7364 for (; inode < nbNodes; inode++) {
7365 face_nodes[inode] = curNodes[inode];
7368 vector<const SMDS_MeshNode *> polygons_nodes;
7369 vector<int> quantities;
7370 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7374 for (int iface = 0; iface < nbNew - 1; iface++) {
7375 int nbNodes = quantities[iface];
7376 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7377 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7378 poly_nodes[ii] = polygons_nodes[inode];
7380 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7381 myLastCreatedElems.Append(newElem);
7383 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7386 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7387 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7388 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7390 if (nbNew > 0) quid = nbNew - 1;
7391 vector<int> newquant(quantities.begin()+quid, quantities.end());
7392 const SMDS_MeshElement* newElem = 0;
7393 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7394 myLastCreatedElems.Append(newElem);
7395 if ( aShapeId && newElem )
7396 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7397 rmElemIds.push_back(elem->GetID());
7400 rmElemIds.push_back(elem->GetID());
7404 else if (elem->GetType() == SMDSAbs_Volume) {
7405 // Polyhedral volume
7406 if (nbUniqueNodes < 4) {
7407 rmElemIds.push_back(elem->GetID());
7410 // each face has to be analyzed in order to check volume validity
7411 const SMDS_VtkVolume* aPolyedre =
7412 dynamic_cast<const SMDS_VtkVolume*>( elem );
7414 int nbFaces = aPolyedre->NbFaces();
7416 vector<const SMDS_MeshNode *> poly_nodes;
7417 vector<int> quantities;
7419 for (int iface = 1; iface <= nbFaces; iface++) {
7420 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7421 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7423 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7424 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7425 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7426 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7427 faceNode = (*nnIt).second;
7429 faceNodes[inode - 1] = faceNode;
7432 SimplifyFace(faceNodes, poly_nodes, quantities);
7435 if (quantities.size() > 3) {
7436 // to be done: remove coincident faces
7439 if (quantities.size() > 3)
7441 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7442 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7443 const SMDS_MeshElement* newElem = 0;
7444 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7445 myLastCreatedElems.Append(newElem);
7446 if ( aShapeId && newElem )
7447 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7448 rmElemIds.push_back(elem->GetID());
7452 rmElemIds.push_back(elem->GetID());
7463 // TODO not all the possible cases are solved. Find something more generic?
7464 switch ( nbNodes ) {
7465 case 2: ///////////////////////////////////// EDGE
7466 isOk = false; break;
7467 case 3: ///////////////////////////////////// TRIANGLE
7468 isOk = false; break;
7470 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7472 else { //////////////////////////////////// QUADRANGLE
7473 if ( nbUniqueNodes < 3 )
7475 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7476 isOk = false; // opposite nodes stick
7477 //MESSAGE("isOk " << isOk);
7480 case 6: ///////////////////////////////////// PENTAHEDRON
7481 if ( nbUniqueNodes == 4 ) {
7482 // ---------------------------------> tetrahedron
7484 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7485 // all top nodes stick: reverse a bottom
7486 uniqueNodes[ 0 ] = curNodes [ 1 ];
7487 uniqueNodes[ 1 ] = curNodes [ 0 ];
7489 else if (nbRepl == 3 &&
7490 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7491 // all bottom nodes stick: set a top before
7492 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7493 uniqueNodes[ 0 ] = curNodes [ 3 ];
7494 uniqueNodes[ 1 ] = curNodes [ 4 ];
7495 uniqueNodes[ 2 ] = curNodes [ 5 ];
7497 else if (nbRepl == 4 &&
7498 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7499 // a lateral face turns into a line: reverse a bottom
7500 uniqueNodes[ 0 ] = curNodes [ 1 ];
7501 uniqueNodes[ 1 ] = curNodes [ 0 ];
7506 else if ( nbUniqueNodes == 5 ) {
7507 // PENTAHEDRON --------------------> 2 tetrahedrons
7508 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7509 // a bottom node sticks with a linked top one
7511 SMDS_MeshElement* newElem =
7512 aMesh->AddVolume(curNodes[ 3 ],
7515 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7516 myLastCreatedElems.Append(newElem);
7518 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7519 // 2. : reverse a bottom
7520 uniqueNodes[ 0 ] = curNodes [ 1 ];
7521 uniqueNodes[ 1 ] = curNodes [ 0 ];
7531 if(elem->IsQuadratic()) { // Quadratic quadrangle
7543 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7546 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7548 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7549 uniqueNodes[0] = curNodes[0];
7550 uniqueNodes[1] = curNodes[2];
7551 uniqueNodes[2] = curNodes[3];
7552 uniqueNodes[3] = curNodes[5];
7553 uniqueNodes[4] = curNodes[6];
7554 uniqueNodes[5] = curNodes[7];
7557 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7558 uniqueNodes[0] = curNodes[0];
7559 uniqueNodes[1] = curNodes[1];
7560 uniqueNodes[2] = curNodes[2];
7561 uniqueNodes[3] = curNodes[4];
7562 uniqueNodes[4] = curNodes[5];
7563 uniqueNodes[5] = curNodes[6];
7566 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7567 uniqueNodes[0] = curNodes[1];
7568 uniqueNodes[1] = curNodes[2];
7569 uniqueNodes[2] = curNodes[3];
7570 uniqueNodes[3] = curNodes[5];
7571 uniqueNodes[4] = curNodes[6];
7572 uniqueNodes[5] = curNodes[0];
7575 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7576 uniqueNodes[0] = curNodes[0];
7577 uniqueNodes[1] = curNodes[1];
7578 uniqueNodes[2] = curNodes[3];
7579 uniqueNodes[3] = curNodes[4];
7580 uniqueNodes[4] = curNodes[6];
7581 uniqueNodes[5] = curNodes[7];
7584 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7585 uniqueNodes[0] = curNodes[0];
7586 uniqueNodes[1] = curNodes[2];
7587 uniqueNodes[2] = curNodes[3];
7588 uniqueNodes[3] = curNodes[1];
7589 uniqueNodes[4] = curNodes[6];
7590 uniqueNodes[5] = curNodes[7];
7593 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7594 uniqueNodes[0] = curNodes[0];
7595 uniqueNodes[1] = curNodes[1];
7596 uniqueNodes[2] = curNodes[2];
7597 uniqueNodes[3] = curNodes[4];
7598 uniqueNodes[4] = curNodes[5];
7599 uniqueNodes[5] = curNodes[7];
7602 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7603 uniqueNodes[0] = curNodes[0];
7604 uniqueNodes[1] = curNodes[1];
7605 uniqueNodes[2] = curNodes[3];
7606 uniqueNodes[3] = curNodes[4];
7607 uniqueNodes[4] = curNodes[2];
7608 uniqueNodes[5] = curNodes[7];
7611 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7612 uniqueNodes[0] = curNodes[0];
7613 uniqueNodes[1] = curNodes[1];
7614 uniqueNodes[2] = curNodes[2];
7615 uniqueNodes[3] = curNodes[4];
7616 uniqueNodes[4] = curNodes[5];
7617 uniqueNodes[5] = curNodes[3];
7622 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7625 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7629 //////////////////////////////////// HEXAHEDRON
7631 SMDS_VolumeTool hexa (elem);
7632 hexa.SetExternalNormal();
7633 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7634 //////////////////////// ---> tetrahedron
7635 for ( int iFace = 0; iFace < 6; iFace++ ) {
7636 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7637 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7638 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7639 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7640 // one face turns into a point ...
7641 int iOppFace = hexa.GetOppFaceIndex( iFace );
7642 ind = hexa.GetFaceNodesIndices( iOppFace );
7644 iUnique = 2; // reverse a tetrahedron bottom
7645 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7646 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7648 else if ( iUnique >= 0 )
7649 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7651 if ( nbStick == 1 ) {
7652 // ... and the opposite one - into a triangle.
7654 ind = hexa.GetFaceNodesIndices( iFace );
7655 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7662 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7663 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7664 for ( int iFace = 0; iFace < 6; iFace++ ) {
7665 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7666 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7667 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7668 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7669 // one face turns into a point ...
7670 int iOppFace = hexa.GetOppFaceIndex( iFace );
7671 ind = hexa.GetFaceNodesIndices( iOppFace );
7673 iUnique = 2; // reverse a tetrahedron 1 bottom
7674 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7675 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7677 else if ( iUnique >= 0 )
7678 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7680 if ( nbStick == 0 ) {
7681 // ... and the opposite one is a quadrangle
7683 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7684 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7687 SMDS_MeshElement* newElem =
7688 aMesh->AddVolume(curNodes[ind[ 0 ]],
7691 curNodes[indTop[ 0 ]]);
7692 myLastCreatedElems.Append(newElem);
7694 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7701 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7702 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7703 // find indices of quad and tri faces
7704 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7705 for ( iFace = 0; iFace < 6; iFace++ ) {
7706 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7708 for ( iCur = 0; iCur < 4; iCur++ )
7709 nodeSet.insert( curNodes[ind[ iCur ]] );
7710 nbUniqueNodes = nodeSet.size();
7711 if ( nbUniqueNodes == 3 )
7712 iTriFace[ nbTri++ ] = iFace;
7713 else if ( nbUniqueNodes == 4 )
7714 iQuadFace[ nbQuad++ ] = iFace;
7716 if (nbQuad == 2 && nbTri == 4 &&
7717 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7718 // 2 opposite quadrangles stuck with a diagonal;
7719 // sample groups of merged indices: (0-4)(2-6)
7720 // --------------------------------------------> 2 tetrahedrons
7721 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7722 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7723 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7724 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7725 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7726 // stuck with 0-2 diagonal
7734 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7735 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7736 // stuck with 1-3 diagonal
7748 uniqueNodes[ 0 ] = curNodes [ i0 ];
7749 uniqueNodes[ 1 ] = curNodes [ i1d ];
7750 uniqueNodes[ 2 ] = curNodes [ i3d ];
7751 uniqueNodes[ 3 ] = curNodes [ i0t ];
7754 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7758 myLastCreatedElems.Append(newElem);
7760 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7763 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7764 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7765 // --------------------------------------------> prism
7766 // find 2 opposite triangles
7768 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7769 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7770 // find indices of kept and replaced nodes
7771 // and fill unique nodes of 2 opposite triangles
7772 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7773 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7774 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7775 // fill unique nodes
7778 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7779 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7780 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7782 // iCur of a linked node of the opposite face (make normals co-directed):
7783 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7784 // check that correspondent corners of triangles are linked
7785 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7788 uniqueNodes[ iUnique ] = n;
7789 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7798 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7804 } // switch ( nbNodes )
7806 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7809 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7810 // Change nodes of polyedre
7811 const SMDS_VtkVolume* aPolyedre =
7812 dynamic_cast<const SMDS_VtkVolume*>( elem );
7814 int nbFaces = aPolyedre->NbFaces();
7816 vector<const SMDS_MeshNode *> poly_nodes;
7817 vector<int> quantities (nbFaces);
7819 for (int iface = 1; iface <= nbFaces; iface++) {
7820 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7821 quantities[iface - 1] = nbFaceNodes;
7823 for (inode = 1; inode <= nbFaceNodes; inode++) {
7824 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7826 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7827 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7828 curNode = (*nnIt).second;
7830 poly_nodes.push_back(curNode);
7833 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7837 //int elemId = elem->GetID();
7838 //MESSAGE("Change regular element or polygon " << elemId);
7839 SMDSAbs_ElementType etyp = elem->GetType();
7840 uniqueNodes.resize(nbUniqueNodes);
7841 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, false);
7844 myLastCreatedElems.Append(newElem);
7846 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7848 aMesh->RemoveElement(elem);
7852 // Remove invalid regular element or invalid polygon
7853 //MESSAGE("Remove invalid " << elem->GetID());
7854 rmElemIds.push_back( elem->GetID() );
7857 } // loop on elements
7859 // Remove bad elements, then equal nodes (order important)
7861 Remove( rmElemIds, false );
7862 Remove( rmNodeIds, true );
7867 // ========================================================
7868 // class : SortableElement
7869 // purpose : allow sorting elements basing on their nodes
7870 // ========================================================
7871 class SortableElement : public set <const SMDS_MeshElement*>
7875 SortableElement( const SMDS_MeshElement* theElem )
7878 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7879 while ( nodeIt->more() )
7880 this->insert( nodeIt->next() );
7883 const SMDS_MeshElement* Get() const
7886 void Set(const SMDS_MeshElement* e) const
7891 mutable const SMDS_MeshElement* myElem;
7894 //=======================================================================
7895 //function : FindEqualElements
7896 //purpose : Return list of group of elements built on the same nodes.
7897 // Search among theElements or in the whole mesh if theElements is empty
7898 //=======================================================================
7899 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7900 TListOfListOfElementsID & theGroupsOfElementsID)
7902 myLastCreatedElems.Clear();
7903 myLastCreatedNodes.Clear();
7905 typedef set<const SMDS_MeshElement*> TElemsSet;
7906 typedef map< SortableElement, int > TMapOfNodeSet;
7907 typedef list<int> TGroupOfElems;
7910 if ( theElements.empty() )
7911 { // get all elements in the mesh
7912 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7913 while ( eIt->more() )
7914 elems.insert( elems.end(), eIt->next());
7917 elems = theElements;
7919 vector< TGroupOfElems > arrayOfGroups;
7920 TGroupOfElems groupOfElems;
7921 TMapOfNodeSet mapOfNodeSet;
7923 TElemsSet::iterator elemIt = elems.begin();
7924 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7925 const SMDS_MeshElement* curElem = *elemIt;
7926 SortableElement SE(curElem);
7929 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7930 if( !(pp.second) ) {
7931 TMapOfNodeSet::iterator& itSE = pp.first;
7932 ind = (*itSE).second;
7933 arrayOfGroups[ind].push_back(curElem->GetID());
7936 groupOfElems.clear();
7937 groupOfElems.push_back(curElem->GetID());
7938 arrayOfGroups.push_back(groupOfElems);
7943 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7944 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7945 groupOfElems = *groupIt;
7946 if ( groupOfElems.size() > 1 ) {
7947 groupOfElems.sort();
7948 theGroupsOfElementsID.push_back(groupOfElems);
7953 //=======================================================================
7954 //function : MergeElements
7955 //purpose : In each given group, substitute all elements by the first one.
7956 //=======================================================================
7958 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7960 myLastCreatedElems.Clear();
7961 myLastCreatedNodes.Clear();
7963 typedef list<int> TListOfIDs;
7964 TListOfIDs rmElemIds; // IDs of elems to remove
7966 SMESHDS_Mesh* aMesh = GetMeshDS();
7968 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7969 while ( groupsIt != theGroupsOfElementsID.end() ) {
7970 TListOfIDs& aGroupOfElemID = *groupsIt;
7971 aGroupOfElemID.sort();
7972 int elemIDToKeep = aGroupOfElemID.front();
7973 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7974 aGroupOfElemID.pop_front();
7975 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7976 while ( idIt != aGroupOfElemID.end() ) {
7977 int elemIDToRemove = *idIt;
7978 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7979 // add the kept element in groups of removed one (PAL15188)
7980 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7981 rmElemIds.push_back( elemIDToRemove );
7987 Remove( rmElemIds, false );
7990 //=======================================================================
7991 //function : MergeEqualElements
7992 //purpose : Remove all but one of elements built on the same nodes.
7993 //=======================================================================
7995 void SMESH_MeshEditor::MergeEqualElements()
7997 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7998 to merge equal elements in the whole mesh */
7999 TListOfListOfElementsID aGroupsOfElementsID;
8000 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8001 MergeElements(aGroupsOfElementsID);
8004 //=======================================================================
8005 //function : FindFaceInSet
8006 //purpose : Return a face having linked nodes n1 and n2 and which is
8007 // - not in avoidSet,
8008 // - in elemSet provided that !elemSet.empty()
8009 // i1 and i2 optionally returns indices of n1 and n2
8010 //=======================================================================
8012 const SMDS_MeshElement*
8013 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8014 const SMDS_MeshNode* n2,
8015 const TIDSortedElemSet& elemSet,
8016 const TIDSortedElemSet& avoidSet,
8022 const SMDS_MeshElement* face = 0;
8024 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8025 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8026 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8028 //MESSAGE("in while ( invElemIt->more() && !face )");
8029 const SMDS_MeshElement* elem = invElemIt->next();
8030 if (avoidSet.count( elem ))
8032 if ( !elemSet.empty() && !elemSet.count( elem ))
8035 i1 = elem->GetNodeIndex( n1 );
8036 // find a n2 linked to n1
8037 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8038 for ( int di = -1; di < 2 && !face; di += 2 )
8040 i2 = (i1+di+nbN) % nbN;
8041 if ( elem->GetNode( i2 ) == n2 )
8044 if ( !face && elem->IsQuadratic())
8046 // analysis for quadratic elements using all nodes
8047 const SMDS_VtkFace* F =
8048 dynamic_cast<const SMDS_VtkFace*>(elem);
8049 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8050 // use special nodes iterator
8051 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8052 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8053 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8055 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8056 if ( n1 == prevN && n2 == n )
8060 else if ( n2 == prevN && n1 == n )
8062 face = elem; swap( i1, i2 );
8068 if ( n1ind ) *n1ind = i1;
8069 if ( n2ind ) *n2ind = i2;
8073 //=======================================================================
8074 //function : findAdjacentFace
8076 //=======================================================================
8078 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8079 const SMDS_MeshNode* n2,
8080 const SMDS_MeshElement* elem)
8082 TIDSortedElemSet elemSet, avoidSet;
8084 avoidSet.insert ( elem );
8085 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8088 //=======================================================================
8089 //function : FindFreeBorder
8091 //=======================================================================
8093 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8095 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8096 const SMDS_MeshNode* theSecondNode,
8097 const SMDS_MeshNode* theLastNode,
8098 list< const SMDS_MeshNode* > & theNodes,
8099 list< const SMDS_MeshElement* >& theFaces)
8101 if ( !theFirstNode || !theSecondNode )
8103 // find border face between theFirstNode and theSecondNode
8104 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8108 theFaces.push_back( curElem );
8109 theNodes.push_back( theFirstNode );
8110 theNodes.push_back( theSecondNode );
8112 //vector<const SMDS_MeshNode*> nodes;
8113 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8114 TIDSortedElemSet foundElems;
8115 bool needTheLast = ( theLastNode != 0 );
8117 while ( nStart != theLastNode ) {
8118 if ( nStart == theFirstNode )
8119 return !needTheLast;
8121 // find all free border faces sharing form nStart
8123 list< const SMDS_MeshElement* > curElemList;
8124 list< const SMDS_MeshNode* > nStartList;
8125 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8126 while ( invElemIt->more() ) {
8127 const SMDS_MeshElement* e = invElemIt->next();
8128 if ( e == curElem || foundElems.insert( e ).second ) {
8130 int iNode = 0, nbNodes = e->NbNodes();
8131 //const SMDS_MeshNode* nodes[nbNodes+1];
8132 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8134 if(e->IsQuadratic()) {
8135 const SMDS_VtkFace* F =
8136 dynamic_cast<const SMDS_VtkFace*>(e);
8137 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8138 // use special nodes iterator
8139 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8140 while( anIter->more() ) {
8141 nodes[ iNode++ ] = cast2Node(anIter->next());
8145 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8146 while ( nIt->more() )
8147 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8149 nodes[ iNode ] = nodes[ 0 ];
8151 for ( iNode = 0; iNode < nbNodes; iNode++ )
8152 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8153 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8154 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8156 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8157 curElemList.push_back( e );
8161 // analyse the found
8163 int nbNewBorders = curElemList.size();
8164 if ( nbNewBorders == 0 ) {
8165 // no free border furthermore
8166 return !needTheLast;
8168 else if ( nbNewBorders == 1 ) {
8169 // one more element found
8171 nStart = nStartList.front();
8172 curElem = curElemList.front();
8173 theFaces.push_back( curElem );
8174 theNodes.push_back( nStart );
8177 // several continuations found
8178 list< const SMDS_MeshElement* >::iterator curElemIt;
8179 list< const SMDS_MeshNode* >::iterator nStartIt;
8180 // check if one of them reached the last node
8181 if ( needTheLast ) {
8182 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8183 curElemIt!= curElemList.end();
8184 curElemIt++, nStartIt++ )
8185 if ( *nStartIt == theLastNode ) {
8186 theFaces.push_back( *curElemIt );
8187 theNodes.push_back( *nStartIt );
8191 // find the best free border by the continuations
8192 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8193 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8194 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8195 curElemIt!= curElemList.end();
8196 curElemIt++, nStartIt++ )
8198 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8199 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8200 // find one more free border
8201 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8205 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8206 // choice: clear a worse one
8207 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8208 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8209 contNodes[ iWorse ].clear();
8210 contFaces[ iWorse ].clear();
8213 if ( contNodes[0].empty() && contNodes[1].empty() )
8216 // append the best free border
8217 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8218 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8219 theNodes.pop_back(); // remove nIgnore
8220 theNodes.pop_back(); // remove nStart
8221 theFaces.pop_back(); // remove curElem
8222 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8223 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8224 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8225 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8228 } // several continuations found
8229 } // while ( nStart != theLastNode )
8234 //=======================================================================
8235 //function : CheckFreeBorderNodes
8236 //purpose : Return true if the tree nodes are on a free border
8237 //=======================================================================
8239 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8240 const SMDS_MeshNode* theNode2,
8241 const SMDS_MeshNode* theNode3)
8243 list< const SMDS_MeshNode* > nodes;
8244 list< const SMDS_MeshElement* > faces;
8245 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8248 //=======================================================================
8249 //function : SewFreeBorder
8251 //=======================================================================
8253 SMESH_MeshEditor::Sew_Error
8254 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8255 const SMDS_MeshNode* theBordSecondNode,
8256 const SMDS_MeshNode* theBordLastNode,
8257 const SMDS_MeshNode* theSideFirstNode,
8258 const SMDS_MeshNode* theSideSecondNode,
8259 const SMDS_MeshNode* theSideThirdNode,
8260 const bool theSideIsFreeBorder,
8261 const bool toCreatePolygons,
8262 const bool toCreatePolyedrs)
8264 myLastCreatedElems.Clear();
8265 myLastCreatedNodes.Clear();
8267 MESSAGE("::SewFreeBorder()");
8268 Sew_Error aResult = SEW_OK;
8270 // ====================================
8271 // find side nodes and elements
8272 // ====================================
8274 list< const SMDS_MeshNode* > nSide[ 2 ];
8275 list< const SMDS_MeshElement* > eSide[ 2 ];
8276 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8277 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8281 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8282 nSide[0], eSide[0])) {
8283 MESSAGE(" Free Border 1 not found " );
8284 aResult = SEW_BORDER1_NOT_FOUND;
8286 if (theSideIsFreeBorder) {
8289 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8290 nSide[1], eSide[1])) {
8291 MESSAGE(" Free Border 2 not found " );
8292 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8295 if ( aResult != SEW_OK )
8298 if (!theSideIsFreeBorder) {
8302 // -------------------------------------------------------------------------
8304 // 1. If nodes to merge are not coincident, move nodes of the free border
8305 // from the coord sys defined by the direction from the first to last
8306 // nodes of the border to the correspondent sys of the side 2
8307 // 2. On the side 2, find the links most co-directed with the correspondent
8308 // links of the free border
8309 // -------------------------------------------------------------------------
8311 // 1. Since sewing may break if there are volumes to split on the side 2,
8312 // we wont move nodes but just compute new coordinates for them
8313 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8314 TNodeXYZMap nBordXYZ;
8315 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8316 list< const SMDS_MeshNode* >::iterator nBordIt;
8318 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8319 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8320 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8321 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8322 double tol2 = 1.e-8;
8323 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8324 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8325 // Need node movement.
8327 // find X and Z axes to create trsf
8328 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8330 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8332 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8335 gp_Ax3 toBordAx( Pb1, Zb, X );
8336 gp_Ax3 fromSideAx( Ps1, Zs, X );
8337 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8339 gp_Trsf toBordSys, fromSide2Sys;
8340 toBordSys.SetTransformation( toBordAx );
8341 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8342 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8345 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8346 const SMDS_MeshNode* n = *nBordIt;
8347 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8348 toBordSys.Transforms( xyz );
8349 fromSide2Sys.Transforms( xyz );
8350 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8354 // just insert nodes XYZ in the nBordXYZ map
8355 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8356 const SMDS_MeshNode* n = *nBordIt;
8357 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8361 // 2. On the side 2, find the links most co-directed with the correspondent
8362 // links of the free border
8364 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8365 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8366 sideNodes.push_back( theSideFirstNode );
8368 bool hasVolumes = false;
8369 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8370 set<long> foundSideLinkIDs, checkedLinkIDs;
8371 SMDS_VolumeTool volume;
8372 //const SMDS_MeshNode* faceNodes[ 4 ];
8374 const SMDS_MeshNode* sideNode;
8375 const SMDS_MeshElement* sideElem;
8376 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8377 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8378 nBordIt = bordNodes.begin();
8380 // border node position and border link direction to compare with
8381 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8382 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8383 // choose next side node by link direction or by closeness to
8384 // the current border node:
8385 bool searchByDir = ( *nBordIt != theBordLastNode );
8387 // find the next node on the Side 2
8389 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8391 checkedLinkIDs.clear();
8392 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8394 // loop on inverse elements of current node (prevSideNode) on the Side 2
8395 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8396 while ( invElemIt->more() )
8398 const SMDS_MeshElement* elem = invElemIt->next();
8399 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8400 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8401 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8402 bool isVolume = volume.Set( elem );
8403 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8404 if ( isVolume ) // --volume
8406 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8407 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8408 if(elem->IsQuadratic()) {
8409 const SMDS_VtkFace* F =
8410 dynamic_cast<const SMDS_VtkFace*>(elem);
8411 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8412 // use special nodes iterator
8413 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8414 while( anIter->more() ) {
8415 nodes[ iNode ] = cast2Node(anIter->next());
8416 if ( nodes[ iNode++ ] == prevSideNode )
8417 iPrevNode = iNode - 1;
8421 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8422 while ( nIt->more() ) {
8423 nodes[ iNode ] = cast2Node( nIt->next() );
8424 if ( nodes[ iNode++ ] == prevSideNode )
8425 iPrevNode = iNode - 1;
8428 // there are 2 links to check
8433 // loop on links, to be precise, on the second node of links
8434 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8435 const SMDS_MeshNode* n = nodes[ iNode ];
8437 if ( !volume.IsLinked( n, prevSideNode ))
8441 if ( iNode ) // a node before prevSideNode
8442 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8443 else // a node after prevSideNode
8444 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8446 // check if this link was already used
8447 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8448 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8449 if (!isJustChecked &&
8450 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8452 // test a link geometrically
8453 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8454 bool linkIsBetter = false;
8455 double dot = 0.0, dist = 0.0;
8456 if ( searchByDir ) { // choose most co-directed link
8457 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8458 linkIsBetter = ( dot > maxDot );
8460 else { // choose link with the node closest to bordPos
8461 dist = ( nextXYZ - bordPos ).SquareModulus();
8462 linkIsBetter = ( dist < minDist );
8464 if ( linkIsBetter ) {
8473 } // loop on inverse elements of prevSideNode
8476 MESSAGE(" Cant find path by links of the Side 2 ");
8477 return SEW_BAD_SIDE_NODES;
8479 sideNodes.push_back( sideNode );
8480 sideElems.push_back( sideElem );
8481 foundSideLinkIDs.insert ( linkID );
8482 prevSideNode = sideNode;
8484 if ( *nBordIt == theBordLastNode )
8485 searchByDir = false;
8487 // find the next border link to compare with
8488 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8489 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8490 // move to next border node if sideNode is before forward border node (bordPos)
8491 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8492 prevBordNode = *nBordIt;
8494 bordPos = nBordXYZ[ *nBordIt ];
8495 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8496 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8500 while ( sideNode != theSideSecondNode );
8502 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8503 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8504 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8506 } // end nodes search on the side 2
8508 // ============================
8509 // sew the border to the side 2
8510 // ============================
8512 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8513 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8515 TListOfListOfNodes nodeGroupsToMerge;
8516 if ( nbNodes[0] == nbNodes[1] ||
8517 ( theSideIsFreeBorder && !theSideThirdNode)) {
8519 // all nodes are to be merged
8521 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8522 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8523 nIt[0]++, nIt[1]++ )
8525 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8526 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8527 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8532 // insert new nodes into the border and the side to get equal nb of segments
8534 // get normalized parameters of nodes on the borders
8535 //double param[ 2 ][ maxNbNodes ];
8537 param[0] = new double [ maxNbNodes ];
8538 param[1] = new double [ maxNbNodes ];
8540 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8541 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8542 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8543 const SMDS_MeshNode* nPrev = *nIt;
8544 double bordLength = 0;
8545 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8546 const SMDS_MeshNode* nCur = *nIt;
8547 gp_XYZ segment (nCur->X() - nPrev->X(),
8548 nCur->Y() - nPrev->Y(),
8549 nCur->Z() - nPrev->Z());
8550 double segmentLen = segment.Modulus();
8551 bordLength += segmentLen;
8552 param[ iBord ][ iNode ] = bordLength;
8555 // normalize within [0,1]
8556 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8557 param[ iBord ][ iNode ] /= bordLength;
8561 // loop on border segments
8562 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8563 int i[ 2 ] = { 0, 0 };
8564 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8565 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8567 TElemOfNodeListMap insertMap;
8568 TElemOfNodeListMap::iterator insertMapIt;
8570 // key: elem to insert nodes into
8571 // value: 2 nodes to insert between + nodes to be inserted
8573 bool next[ 2 ] = { false, false };
8575 // find min adjacent segment length after sewing
8576 double nextParam = 10., prevParam = 0;
8577 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8578 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8579 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8580 if ( i[ iBord ] > 0 )
8581 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8583 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8584 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8585 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8587 // choose to insert or to merge nodes
8588 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8589 if ( Abs( du ) <= minSegLen * 0.2 ) {
8592 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8593 const SMDS_MeshNode* n0 = *nIt[0];
8594 const SMDS_MeshNode* n1 = *nIt[1];
8595 nodeGroupsToMerge.back().push_back( n1 );
8596 nodeGroupsToMerge.back().push_back( n0 );
8597 // position of node of the border changes due to merge
8598 param[ 0 ][ i[0] ] += du;
8599 // move n1 for the sake of elem shape evaluation during insertion.
8600 // n1 will be removed by MergeNodes() anyway
8601 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8602 next[0] = next[1] = true;
8607 int intoBord = ( du < 0 ) ? 0 : 1;
8608 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8609 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8610 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8611 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8612 if ( intoBord == 1 ) {
8613 // move node of the border to be on a link of elem of the side
8614 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8615 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8616 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8617 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8618 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8620 insertMapIt = insertMap.find( elem );
8621 bool notFound = ( insertMapIt == insertMap.end() );
8622 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8624 // insert into another link of the same element:
8625 // 1. perform insertion into the other link of the elem
8626 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8627 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8628 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8629 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8630 // 2. perform insertion into the link of adjacent faces
8632 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8634 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8638 if (toCreatePolyedrs) {
8639 // perform insertion into the links of adjacent volumes
8640 UpdateVolumes(n12, n22, nodeList);
8642 // 3. find an element appeared on n1 and n2 after the insertion
8643 insertMap.erase( elem );
8644 elem = findAdjacentFace( n1, n2, 0 );
8646 if ( notFound || otherLink ) {
8647 // add element and nodes of the side into the insertMap
8648 insertMapIt = insertMap.insert
8649 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8650 (*insertMapIt).second.push_back( n1 );
8651 (*insertMapIt).second.push_back( n2 );
8653 // add node to be inserted into elem
8654 (*insertMapIt).second.push_back( nIns );
8655 next[ 1 - intoBord ] = true;
8658 // go to the next segment
8659 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8660 if ( next[ iBord ] ) {
8661 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8663 nPrev[ iBord ] = *nIt[ iBord ];
8664 nIt[ iBord ]++; i[ iBord ]++;
8668 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8670 // perform insertion of nodes into elements
8672 for (insertMapIt = insertMap.begin();
8673 insertMapIt != insertMap.end();
8676 const SMDS_MeshElement* elem = (*insertMapIt).first;
8677 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8678 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8679 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8681 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8683 if ( !theSideIsFreeBorder ) {
8684 // look for and insert nodes into the faces adjacent to elem
8686 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8688 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8693 if (toCreatePolyedrs) {
8694 // perform insertion into the links of adjacent volumes
8695 UpdateVolumes(n1, n2, nodeList);
8701 } // end: insert new nodes
8703 MergeNodes ( nodeGroupsToMerge );
8708 //=======================================================================
8709 //function : InsertNodesIntoLink
8710 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8711 // and theBetweenNode2 and split theElement
8712 //=======================================================================
8714 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8715 const SMDS_MeshNode* theBetweenNode1,
8716 const SMDS_MeshNode* theBetweenNode2,
8717 list<const SMDS_MeshNode*>& theNodesToInsert,
8718 const bool toCreatePoly)
8720 if ( theFace->GetType() != SMDSAbs_Face ) return;
8722 // find indices of 2 link nodes and of the rest nodes
8723 int iNode = 0, il1, il2, i3, i4;
8724 il1 = il2 = i3 = i4 = -1;
8725 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8726 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8728 if(theFace->IsQuadratic()) {
8729 const SMDS_VtkFace* F =
8730 dynamic_cast<const SMDS_VtkFace*>(theFace);
8731 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8732 // use special nodes iterator
8733 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8734 while( anIter->more() ) {
8735 const SMDS_MeshNode* n = cast2Node(anIter->next());
8736 if ( n == theBetweenNode1 )
8738 else if ( n == theBetweenNode2 )
8744 nodes[ iNode++ ] = n;
8748 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8749 while ( nodeIt->more() ) {
8750 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8751 if ( n == theBetweenNode1 )
8753 else if ( n == theBetweenNode2 )
8759 nodes[ iNode++ ] = n;
8762 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8765 // arrange link nodes to go one after another regarding the face orientation
8766 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8767 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8772 aNodesToInsert.reverse();
8774 // check that not link nodes of a quadrangles are in good order
8775 int nbFaceNodes = theFace->NbNodes();
8776 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8782 if (toCreatePoly || theFace->IsPoly()) {
8785 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8787 // add nodes of face up to first node of link
8790 if(theFace->IsQuadratic()) {
8791 const SMDS_VtkFace* F =
8792 dynamic_cast<const SMDS_VtkFace*>(theFace);
8793 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8794 // use special nodes iterator
8795 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8796 while( anIter->more() && !isFLN ) {
8797 const SMDS_MeshNode* n = cast2Node(anIter->next());
8798 poly_nodes[iNode++] = n;
8799 if (n == nodes[il1]) {
8803 // add nodes to insert
8804 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8805 for (; nIt != aNodesToInsert.end(); nIt++) {
8806 poly_nodes[iNode++] = *nIt;
8808 // add nodes of face starting from last node of link
8809 while ( anIter->more() ) {
8810 poly_nodes[iNode++] = cast2Node(anIter->next());
8814 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8815 while ( nodeIt->more() && !isFLN ) {
8816 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8817 poly_nodes[iNode++] = n;
8818 if (n == nodes[il1]) {
8822 // add nodes to insert
8823 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8824 for (; nIt != aNodesToInsert.end(); nIt++) {
8825 poly_nodes[iNode++] = *nIt;
8827 // add nodes of face starting from last node of link
8828 while ( nodeIt->more() ) {
8829 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8830 poly_nodes[iNode++] = n;
8834 // edit or replace the face
8835 SMESHDS_Mesh *aMesh = GetMeshDS();
8837 if (theFace->IsPoly()) {
8838 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8841 int aShapeId = FindShape( theFace );
8843 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8844 myLastCreatedElems.Append(newElem);
8845 if ( aShapeId && newElem )
8846 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8848 aMesh->RemoveElement(theFace);
8853 SMESHDS_Mesh *aMesh = GetMeshDS();
8854 if( !theFace->IsQuadratic() ) {
8856 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8857 int nbLinkNodes = 2 + aNodesToInsert.size();
8858 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8859 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8860 linkNodes[ 0 ] = nodes[ il1 ];
8861 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8862 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8863 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8864 linkNodes[ iNode++ ] = *nIt;
8866 // decide how to split a quadrangle: compare possible variants
8867 // and choose which of splits to be a quadrangle
8868 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8869 if ( nbFaceNodes == 3 ) {
8870 iBestQuad = nbSplits;
8873 else if ( nbFaceNodes == 4 ) {
8874 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8875 double aBestRate = DBL_MAX;
8876 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8878 double aBadRate = 0;
8879 // evaluate elements quality
8880 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8881 if ( iSplit == iQuad ) {
8882 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8886 aBadRate += getBadRate( &quad, aCrit );
8889 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8891 nodes[ iSplit < iQuad ? i4 : i3 ]);
8892 aBadRate += getBadRate( &tria, aCrit );
8896 if ( aBadRate < aBestRate ) {
8898 aBestRate = aBadRate;
8903 // create new elements
8904 int aShapeId = FindShape( theFace );
8907 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8908 SMDS_MeshElement* newElem = 0;
8909 if ( iSplit == iBestQuad )
8910 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8915 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8917 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8918 myLastCreatedElems.Append(newElem);
8919 if ( aShapeId && newElem )
8920 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8923 // change nodes of theFace
8924 const SMDS_MeshNode* newNodes[ 4 ];
8925 newNodes[ 0 ] = linkNodes[ i1 ];
8926 newNodes[ 1 ] = linkNodes[ i2 ];
8927 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8928 newNodes[ 3 ] = nodes[ i4 ];
8929 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8930 const SMDS_MeshElement* newElem = 0;
8931 if (iSplit == iBestQuad)
8932 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8934 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8935 myLastCreatedElems.Append(newElem);
8936 if ( aShapeId && newElem )
8937 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8938 } // end if(!theFace->IsQuadratic())
8939 else { // theFace is quadratic
8940 // we have to split theFace on simple triangles and one simple quadrangle
8942 int nbshift = tmp*2;
8943 // shift nodes in nodes[] by nbshift
8945 for(i=0; i<nbshift; i++) {
8946 const SMDS_MeshNode* n = nodes[0];
8947 for(j=0; j<nbFaceNodes-1; j++) {
8948 nodes[j] = nodes[j+1];
8950 nodes[nbFaceNodes-1] = n;
8952 il1 = il1 - nbshift;
8953 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8954 // n0 n1 n2 n0 n1 n2
8955 // +-----+-----+ +-----+-----+
8964 // create new elements
8965 int aShapeId = FindShape( theFace );
8968 if(nbFaceNodes==6) { // quadratic triangle
8969 SMDS_MeshElement* newElem =
8970 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8971 myLastCreatedElems.Append(newElem);
8972 if ( aShapeId && newElem )
8973 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8974 if(theFace->IsMediumNode(nodes[il1])) {
8975 // create quadrangle
8976 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8977 myLastCreatedElems.Append(newElem);
8978 if ( aShapeId && newElem )
8979 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8985 // create quadrangle
8986 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8987 myLastCreatedElems.Append(newElem);
8988 if ( aShapeId && newElem )
8989 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8995 else { // nbFaceNodes==8 - quadratic quadrangle
8996 SMDS_MeshElement* newElem =
8997 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8998 myLastCreatedElems.Append(newElem);
8999 if ( aShapeId && newElem )
9000 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9001 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9002 myLastCreatedElems.Append(newElem);
9003 if ( aShapeId && newElem )
9004 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9005 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9006 myLastCreatedElems.Append(newElem);
9007 if ( aShapeId && newElem )
9008 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9009 if(theFace->IsMediumNode(nodes[il1])) {
9010 // create quadrangle
9011 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9012 myLastCreatedElems.Append(newElem);
9013 if ( aShapeId && newElem )
9014 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9020 // create quadrangle
9021 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9022 myLastCreatedElems.Append(newElem);
9023 if ( aShapeId && newElem )
9024 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9030 // create needed triangles using n1,n2,n3 and inserted nodes
9031 int nbn = 2 + aNodesToInsert.size();
9032 //const SMDS_MeshNode* aNodes[nbn];
9033 vector<const SMDS_MeshNode*> aNodes(nbn);
9034 aNodes[0] = nodes[n1];
9035 aNodes[nbn-1] = nodes[n2];
9036 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9037 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9038 aNodes[iNode++] = *nIt;
9040 for(i=1; i<nbn; i++) {
9041 SMDS_MeshElement* newElem =
9042 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9043 myLastCreatedElems.Append(newElem);
9044 if ( aShapeId && newElem )
9045 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9049 aMesh->RemoveElement(theFace);
9052 //=======================================================================
9053 //function : UpdateVolumes
9055 //=======================================================================
9056 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9057 const SMDS_MeshNode* theBetweenNode2,
9058 list<const SMDS_MeshNode*>& theNodesToInsert)
9060 myLastCreatedElems.Clear();
9061 myLastCreatedNodes.Clear();
9063 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9064 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9065 const SMDS_MeshElement* elem = invElemIt->next();
9067 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9068 SMDS_VolumeTool aVolume (elem);
9069 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9072 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9073 int iface, nbFaces = aVolume.NbFaces();
9074 vector<const SMDS_MeshNode *> poly_nodes;
9075 vector<int> quantities (nbFaces);
9077 for (iface = 0; iface < nbFaces; iface++) {
9078 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9079 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9080 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9082 for (int inode = 0; inode < nbFaceNodes; inode++) {
9083 poly_nodes.push_back(faceNodes[inode]);
9085 if (nbInserted == 0) {
9086 if (faceNodes[inode] == theBetweenNode1) {
9087 if (faceNodes[inode + 1] == theBetweenNode2) {
9088 nbInserted = theNodesToInsert.size();
9090 // add nodes to insert
9091 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9092 for (; nIt != theNodesToInsert.end(); nIt++) {
9093 poly_nodes.push_back(*nIt);
9097 else if (faceNodes[inode] == theBetweenNode2) {
9098 if (faceNodes[inode + 1] == theBetweenNode1) {
9099 nbInserted = theNodesToInsert.size();
9101 // add nodes to insert in reversed order
9102 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9104 for (; nIt != theNodesToInsert.begin(); nIt--) {
9105 poly_nodes.push_back(*nIt);
9107 poly_nodes.push_back(*nIt);
9114 quantities[iface] = nbFaceNodes + nbInserted;
9117 // Replace or update the volume
9118 SMESHDS_Mesh *aMesh = GetMeshDS();
9120 if (elem->IsPoly()) {
9121 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9125 int aShapeId = FindShape( elem );
9127 SMDS_MeshElement* newElem =
9128 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9129 myLastCreatedElems.Append(newElem);
9130 if (aShapeId && newElem)
9131 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9133 aMesh->RemoveElement(elem);
9138 //=======================================================================
9140 * \brief Convert elements contained in a submesh to quadratic
9141 * \retval int - nb of checked elements
9143 //=======================================================================
9145 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9146 SMESH_MesherHelper& theHelper,
9147 const bool theForce3d)
9150 if( !theSm ) return nbElem;
9152 vector<int> nbNodeInFaces;
9153 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9154 while(ElemItr->more())
9157 const SMDS_MeshElement* elem = ElemItr->next();
9158 if( !elem || elem->IsQuadratic() ) continue;
9160 int id = elem->GetID();
9161 //MESSAGE("elem " << id);
9162 id = 0; // get a free number for new elements
9163 int nbNodes = elem->NbNodes();
9164 SMDSAbs_ElementType aType = elem->GetType();
9166 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9167 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9168 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9170 const SMDS_MeshElement* NewElem = 0;
9176 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9184 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9187 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9190 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9195 case SMDSAbs_Volume :
9200 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9203 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9206 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9209 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9210 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9213 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9220 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9222 theSm->AddElement( NewElem );
9224 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9226 // if (!GetMeshDS()->isCompacted())
9227 // GetMeshDS()->compactMesh();
9231 //=======================================================================
9232 //function : ConvertToQuadratic
9234 //=======================================================================
9235 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9237 SMESHDS_Mesh* meshDS = GetMeshDS();
9239 SMESH_MesherHelper aHelper(*myMesh);
9240 aHelper.SetIsQuadratic( true );
9242 int nbCheckedElems = 0;
9243 if ( myMesh->HasShapeToMesh() )
9245 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9247 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9248 while ( smIt->more() ) {
9249 SMESH_subMesh* sm = smIt->next();
9250 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9251 aHelper.SetSubShape( sm->GetSubShape() );
9252 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9257 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9258 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9260 SMESHDS_SubMesh *smDS = 0;
9261 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9262 while(aEdgeItr->more())
9264 const SMDS_MeshEdge* edge = aEdgeItr->next();
9265 if(edge && !edge->IsQuadratic())
9267 int id = edge->GetID();
9268 //MESSAGE("edge->GetID() " << id);
9269 const SMDS_MeshNode* n1 = edge->GetNode(0);
9270 const SMDS_MeshNode* n2 = edge->GetNode(1);
9272 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9274 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9275 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9278 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9279 while(aFaceItr->more())
9281 const SMDS_MeshFace* face = aFaceItr->next();
9282 if(!face || face->IsQuadratic() ) continue;
9284 int id = face->GetID();
9285 int nbNodes = face->NbNodes();
9286 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9288 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9290 SMDS_MeshFace * NewFace = 0;
9294 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9297 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9300 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9302 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9304 vector<int> nbNodeInFaces;
9305 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9306 while(aVolumeItr->more())
9308 const SMDS_MeshVolume* volume = aVolumeItr->next();
9309 if(!volume || volume->IsQuadratic() ) continue;
9311 int id = volume->GetID();
9312 int nbNodes = volume->NbNodes();
9313 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9314 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9315 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9317 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9319 SMDS_MeshVolume * NewVolume = 0;
9323 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9324 nodes[3], id, theForce3d );
9327 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9328 nodes[3], nodes[4], id, theForce3d);
9331 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9332 nodes[3], nodes[4], nodes[5], id, theForce3d);
9335 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9336 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9339 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9341 ReplaceElemInGroups(volume, NewVolume, meshDS);
9345 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9346 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9347 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9348 aHelper.FixQuadraticElements();
9350 if (!GetMeshDS()->isCompacted())
9351 GetMeshDS()->compactMesh();
9354 //=======================================================================
9356 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9357 * \retval int - nb of checked elements
9359 //=======================================================================
9361 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9362 SMDS_ElemIteratorPtr theItr,
9363 const int theShapeID)
9366 SMESHDS_Mesh* meshDS = GetMeshDS();
9367 const bool notFromGroups = false;
9369 while( theItr->more() )
9371 const SMDS_MeshElement* elem = theItr->next();
9373 if( elem && elem->IsQuadratic())
9375 int id = elem->GetID();
9376 int nbNodes = elem->NbNodes();
9377 vector<const SMDS_MeshNode *> nodes, mediumNodes;
9378 nodes.reserve( nbNodes );
9379 mediumNodes.reserve( nbNodes );
9381 for(int i = 0; i < nbNodes; i++)
9383 const SMDS_MeshNode* n = elem->GetNode(i);
9385 if( elem->IsMediumNode( n ) )
9386 mediumNodes.push_back( n );
9388 nodes.push_back( n );
9390 if( nodes.empty() ) continue;
9391 SMDSAbs_ElementType aType = elem->GetType();
9393 //remove old quadratic element
9394 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9396 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9397 ReplaceElemInGroups(elem, NewElem, meshDS);
9398 if( theSm && NewElem )
9399 theSm->AddElement( NewElem );
9401 // remove medium nodes
9402 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9403 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9404 const SMDS_MeshNode* n = *nIt;
9405 if ( n->NbInverseElements() == 0 ) {
9406 if ( n->getshapeId() != theShapeID )
9407 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9408 ( n->getshapeId() ));
9410 meshDS->RemoveFreeNode( n, theSm );
9418 //=======================================================================
9419 //function : ConvertFromQuadratic
9421 //=======================================================================
9422 bool SMESH_MeshEditor::ConvertFromQuadratic()
9424 int nbCheckedElems = 0;
9425 if ( myMesh->HasShapeToMesh() )
9427 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9429 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9430 while ( smIt->more() ) {
9431 SMESH_subMesh* sm = smIt->next();
9432 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9433 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9439 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9440 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9442 SMESHDS_SubMesh *aSM = 0;
9443 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9449 //=======================================================================
9450 //function : SewSideElements
9452 //=======================================================================
9454 SMESH_MeshEditor::Sew_Error
9455 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9456 TIDSortedElemSet& theSide2,
9457 const SMDS_MeshNode* theFirstNode1,
9458 const SMDS_MeshNode* theFirstNode2,
9459 const SMDS_MeshNode* theSecondNode1,
9460 const SMDS_MeshNode* theSecondNode2)
9462 myLastCreatedElems.Clear();
9463 myLastCreatedNodes.Clear();
9465 MESSAGE ("::::SewSideElements()");
9466 if ( theSide1.size() != theSide2.size() )
9467 return SEW_DIFF_NB_OF_ELEMENTS;
9469 Sew_Error aResult = SEW_OK;
9471 // 1. Build set of faces representing each side
9472 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9473 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9475 // =======================================================================
9476 // 1. Build set of faces representing each side:
9477 // =======================================================================
9478 // a. build set of nodes belonging to faces
9479 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9480 // c. create temporary faces representing side of volumes if correspondent
9481 // face does not exist
9483 SMESHDS_Mesh* aMesh = GetMeshDS();
9484 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9485 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9486 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9487 set<const SMDS_MeshElement*> volSet1, volSet2;
9488 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9489 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9490 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9491 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9492 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9493 int iSide, iFace, iNode;
9495 list<const SMDS_MeshElement* > tempFaceList;
9496 for ( iSide = 0; iSide < 2; iSide++ ) {
9497 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9498 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9499 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9500 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9501 set<const SMDS_MeshElement*>::iterator vIt;
9502 TIDSortedElemSet::iterator eIt;
9503 set<const SMDS_MeshNode*>::iterator nIt;
9505 // check that given nodes belong to given elements
9506 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9507 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9508 int firstIndex = -1, secondIndex = -1;
9509 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9510 const SMDS_MeshElement* elem = *eIt;
9511 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9512 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9513 if ( firstIndex > -1 && secondIndex > -1 ) break;
9515 if ( firstIndex < 0 || secondIndex < 0 ) {
9516 // we can simply return until temporary faces created
9517 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9520 // -----------------------------------------------------------
9521 // 1a. Collect nodes of existing faces
9522 // and build set of face nodes in order to detect missing
9523 // faces corresponding to sides of volumes
9524 // -----------------------------------------------------------
9526 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9528 // loop on the given element of a side
9529 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9530 //const SMDS_MeshElement* elem = *eIt;
9531 const SMDS_MeshElement* elem = *eIt;
9532 if ( elem->GetType() == SMDSAbs_Face ) {
9533 faceSet->insert( elem );
9534 set <const SMDS_MeshNode*> faceNodeSet;
9535 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9536 while ( nodeIt->more() ) {
9537 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9538 nodeSet->insert( n );
9539 faceNodeSet.insert( n );
9541 setOfFaceNodeSet.insert( faceNodeSet );
9543 else if ( elem->GetType() == SMDSAbs_Volume )
9544 volSet->insert( elem );
9546 // ------------------------------------------------------------------------------
9547 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9548 // ------------------------------------------------------------------------------
9550 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9551 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9552 while ( fIt->more() ) { // loop on faces sharing a node
9553 const SMDS_MeshElement* f = fIt->next();
9554 if ( faceSet->find( f ) == faceSet->end() ) {
9555 // check if all nodes are in nodeSet and
9556 // complete setOfFaceNodeSet if they are
9557 set <const SMDS_MeshNode*> faceNodeSet;
9558 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9559 bool allInSet = true;
9560 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9561 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9562 if ( nodeSet->find( n ) == nodeSet->end() )
9565 faceNodeSet.insert( n );
9568 faceSet->insert( f );
9569 setOfFaceNodeSet.insert( faceNodeSet );
9575 // -------------------------------------------------------------------------
9576 // 1c. Create temporary faces representing sides of volumes if correspondent
9577 // face does not exist
9578 // -------------------------------------------------------------------------
9580 if ( !volSet->empty() ) {
9581 //int nodeSetSize = nodeSet->size();
9583 // loop on given volumes
9584 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9585 SMDS_VolumeTool vol (*vIt);
9586 // loop on volume faces: find free faces
9587 // --------------------------------------
9588 list<const SMDS_MeshElement* > freeFaceList;
9589 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9590 if ( !vol.IsFreeFace( iFace ))
9592 // check if there is already a face with same nodes in a face set
9593 const SMDS_MeshElement* aFreeFace = 0;
9594 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9595 int nbNodes = vol.NbFaceNodes( iFace );
9596 set <const SMDS_MeshNode*> faceNodeSet;
9597 vol.GetFaceNodes( iFace, faceNodeSet );
9598 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9600 // no such a face is given but it still can exist, check it
9601 if ( nbNodes == 3 ) {
9602 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9604 else if ( nbNodes == 4 ) {
9605 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9608 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9609 aFreeFace = aMesh->FindFace(poly_nodes);
9613 // create a temporary face
9614 if ( nbNodes == 3 ) {
9615 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9616 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9618 else if ( nbNodes == 4 ) {
9619 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9620 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9623 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9624 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9625 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9629 freeFaceList.push_back( aFreeFace );
9630 tempFaceList.push_back( aFreeFace );
9633 } // loop on faces of a volume
9635 // choose one of several free faces
9636 // --------------------------------------
9637 if ( freeFaceList.size() > 1 ) {
9638 // choose a face having max nb of nodes shared by other elems of a side
9639 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9640 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9641 while ( fIt != freeFaceList.end() ) { // loop on free faces
9642 int nbSharedNodes = 0;
9643 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9644 while ( nodeIt->more() ) { // loop on free face nodes
9645 const SMDS_MeshNode* n =
9646 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9647 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9648 while ( invElemIt->more() ) {
9649 const SMDS_MeshElement* e = invElemIt->next();
9650 if ( faceSet->find( e ) != faceSet->end() )
9652 if ( elemSet->find( e ) != elemSet->end() )
9656 if ( nbSharedNodes >= maxNbNodes ) {
9657 maxNbNodes = nbSharedNodes;
9661 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9663 if ( freeFaceList.size() > 1 )
9665 // could not choose one face, use another way
9666 // choose a face most close to the bary center of the opposite side
9667 gp_XYZ aBC( 0., 0., 0. );
9668 set <const SMDS_MeshNode*> addedNodes;
9669 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9670 eIt = elemSet2->begin();
9671 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9672 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9673 while ( nodeIt->more() ) { // loop on free face nodes
9674 const SMDS_MeshNode* n =
9675 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9676 if ( addedNodes.insert( n ).second )
9677 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9680 aBC /= addedNodes.size();
9681 double minDist = DBL_MAX;
9682 fIt = freeFaceList.begin();
9683 while ( fIt != freeFaceList.end() ) { // loop on free faces
9685 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9686 while ( nodeIt->more() ) { // loop on free face nodes
9687 const SMDS_MeshNode* n =
9688 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9689 gp_XYZ p( n->X(),n->Y(),n->Z() );
9690 dist += ( aBC - p ).SquareModulus();
9692 if ( dist < minDist ) {
9694 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9697 fIt = freeFaceList.erase( fIt++ );
9700 } // choose one of several free faces of a volume
9702 if ( freeFaceList.size() == 1 ) {
9703 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9704 faceSet->insert( aFreeFace );
9705 // complete a node set with nodes of a found free face
9706 // for ( iNode = 0; iNode < ; iNode++ )
9707 // nodeSet->insert( fNodes[ iNode ] );
9710 } // loop on volumes of a side
9712 // // complete a set of faces if new nodes in a nodeSet appeared
9713 // // ----------------------------------------------------------
9714 // if ( nodeSetSize != nodeSet->size() ) {
9715 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9716 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9717 // while ( fIt->more() ) { // loop on faces sharing a node
9718 // const SMDS_MeshElement* f = fIt->next();
9719 // if ( faceSet->find( f ) == faceSet->end() ) {
9720 // // check if all nodes are in nodeSet and
9721 // // complete setOfFaceNodeSet if they are
9722 // set <const SMDS_MeshNode*> faceNodeSet;
9723 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9724 // bool allInSet = true;
9725 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9726 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9727 // if ( nodeSet->find( n ) == nodeSet->end() )
9728 // allInSet = false;
9730 // faceNodeSet.insert( n );
9732 // if ( allInSet ) {
9733 // faceSet->insert( f );
9734 // setOfFaceNodeSet.insert( faceNodeSet );
9740 } // Create temporary faces, if there are volumes given
9743 if ( faceSet1.size() != faceSet2.size() ) {
9744 // delete temporary faces: they are in reverseElements of actual nodes
9745 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9746 // while ( tmpFaceIt->more() )
9747 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9748 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9749 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9750 // aMesh->RemoveElement(*tmpFaceIt);
9751 MESSAGE("Diff nb of faces");
9752 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9755 // ============================================================
9756 // 2. Find nodes to merge:
9757 // bind a node to remove to a node to put instead
9758 // ============================================================
9760 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9761 if ( theFirstNode1 != theFirstNode2 )
9762 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9763 if ( theSecondNode1 != theSecondNode2 )
9764 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9766 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9767 set< long > linkIdSet; // links to process
9768 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9770 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9771 list< NLink > linkList[2];
9772 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9773 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9774 // loop on links in linkList; find faces by links and append links
9775 // of the found faces to linkList
9776 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9777 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9778 NLink link[] = { *linkIt[0], *linkIt[1] };
9779 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9780 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9783 // by links, find faces in the face sets,
9784 // and find indices of link nodes in the found faces;
9785 // in a face set, there is only one or no face sharing a link
9786 // ---------------------------------------------------------------
9788 const SMDS_MeshElement* face[] = { 0, 0 };
9789 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9790 vector<const SMDS_MeshNode*> fnodes1(9);
9791 vector<const SMDS_MeshNode*> fnodes2(9);
9792 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9793 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9794 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9795 int iLinkNode[2][2];
9796 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9797 const SMDS_MeshNode* n1 = link[iSide].first;
9798 const SMDS_MeshNode* n2 = link[iSide].second;
9799 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9800 set< const SMDS_MeshElement* > fMap;
9801 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9802 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9803 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9804 while ( fIt->more() ) { // loop on faces sharing a node
9805 const SMDS_MeshElement* f = fIt->next();
9806 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9807 ! fMap.insert( f ).second ) // f encounters twice
9809 if ( face[ iSide ] ) {
9810 MESSAGE( "2 faces per link " );
9811 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9815 faceSet->erase( f );
9816 // get face nodes and find ones of a link
9821 fnodes1.resize(f->NbNodes()+1);
9822 notLinkNodes1.resize(f->NbNodes()-2);
9825 fnodes2.resize(f->NbNodes()+1);
9826 notLinkNodes2.resize(f->NbNodes()-2);
9829 if(!f->IsQuadratic()) {
9830 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9831 while ( nIt->more() ) {
9832 const SMDS_MeshNode* n =
9833 static_cast<const SMDS_MeshNode*>( nIt->next() );
9835 iLinkNode[ iSide ][ 0 ] = iNode;
9837 else if ( n == n2 ) {
9838 iLinkNode[ iSide ][ 1 ] = iNode;
9840 //else if ( notLinkNodes[ iSide ][ 0 ] )
9841 // notLinkNodes[ iSide ][ 1 ] = n;
9843 // notLinkNodes[ iSide ][ 0 ] = n;
9847 notLinkNodes1[nbl] = n;
9848 //notLinkNodes1.push_back(n);
9850 notLinkNodes2[nbl] = n;
9851 //notLinkNodes2.push_back(n);
9853 //faceNodes[ iSide ][ iNode++ ] = n;
9855 fnodes1[iNode++] = n;
9858 fnodes2[iNode++] = n;
9862 else { // f->IsQuadratic()
9863 const SMDS_VtkFace* F =
9864 dynamic_cast<const SMDS_VtkFace*>(f);
9865 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9866 // use special nodes iterator
9867 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9868 while ( anIter->more() ) {
9869 const SMDS_MeshNode* n =
9870 static_cast<const SMDS_MeshNode*>( anIter->next() );
9872 iLinkNode[ iSide ][ 0 ] = iNode;
9874 else if ( n == n2 ) {
9875 iLinkNode[ iSide ][ 1 ] = iNode;
9880 notLinkNodes1[nbl] = n;
9883 notLinkNodes2[nbl] = n;
9887 fnodes1[iNode++] = n;
9890 fnodes2[iNode++] = n;
9894 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9896 fnodes1[iNode] = fnodes1[0];
9899 fnodes2[iNode] = fnodes1[0];
9906 // check similarity of elements of the sides
9907 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9908 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9909 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9910 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9913 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9915 break; // do not return because it s necessary to remove tmp faces
9918 // set nodes to merge
9919 // -------------------
9921 if ( face[0] && face[1] ) {
9922 int nbNodes = face[0]->NbNodes();
9923 if ( nbNodes != face[1]->NbNodes() ) {
9924 MESSAGE("Diff nb of face nodes");
9925 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9926 break; // do not return because it s necessary to remove tmp faces
9928 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9929 if ( nbNodes == 3 ) {
9930 //nReplaceMap.insert( TNodeNodeMap::value_type
9931 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9932 nReplaceMap.insert( TNodeNodeMap::value_type
9933 ( notLinkNodes1[0], notLinkNodes2[0] ));
9936 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9937 // analyse link orientation in faces
9938 int i1 = iLinkNode[ iSide ][ 0 ];
9939 int i2 = iLinkNode[ iSide ][ 1 ];
9940 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9941 // if notLinkNodes are the first and the last ones, then
9942 // their order does not correspond to the link orientation
9943 if (( i1 == 1 && i2 == 2 ) ||
9944 ( i1 == 2 && i2 == 1 ))
9945 reverse[ iSide ] = !reverse[ iSide ];
9947 if ( reverse[0] == reverse[1] ) {
9948 //nReplaceMap.insert( TNodeNodeMap::value_type
9949 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9950 //nReplaceMap.insert( TNodeNodeMap::value_type
9951 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9952 for(int nn=0; nn<nbNodes-2; nn++) {
9953 nReplaceMap.insert( TNodeNodeMap::value_type
9954 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9958 //nReplaceMap.insert( TNodeNodeMap::value_type
9959 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9960 //nReplaceMap.insert( TNodeNodeMap::value_type
9961 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9962 for(int nn=0; nn<nbNodes-2; nn++) {
9963 nReplaceMap.insert( TNodeNodeMap::value_type
9964 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9969 // add other links of the faces to linkList
9970 // -----------------------------------------
9972 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9973 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9974 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9975 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9976 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9977 if ( !iter_isnew.second ) { // already in a set: no need to process
9978 linkIdSet.erase( iter_isnew.first );
9980 else // new in set == encountered for the first time: add
9982 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9983 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9984 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9985 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9986 linkList[0].push_back ( NLink( n1, n2 ));
9987 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9991 } // loop on link lists
9993 if ( aResult == SEW_OK &&
9994 ( linkIt[0] != linkList[0].end() ||
9995 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9996 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9997 " " << (faceSetPtr[1]->empty()));
9998 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10001 // ====================================================================
10002 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10003 // ====================================================================
10005 // delete temporary faces: they are in reverseElements of actual nodes
10006 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10007 // while ( tmpFaceIt->more() )
10008 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10009 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10010 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10011 // aMesh->RemoveElement(*tmpFaceIt);
10013 if ( aResult != SEW_OK)
10016 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10017 // loop on nodes replacement map
10018 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10019 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10020 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10021 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10022 nodeIDsToRemove.push_back( nToRemove->GetID() );
10023 // loop on elements sharing nToRemove
10024 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10025 while ( invElemIt->more() ) {
10026 const SMDS_MeshElement* e = invElemIt->next();
10027 // get a new suite of nodes: make replacement
10028 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10029 vector< const SMDS_MeshNode*> nodes( nbNodes );
10030 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10031 while ( nIt->more() ) {
10032 const SMDS_MeshNode* n =
10033 static_cast<const SMDS_MeshNode*>( nIt->next() );
10034 nnIt = nReplaceMap.find( n );
10035 if ( nnIt != nReplaceMap.end() ) {
10037 n = (*nnIt).second;
10041 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10042 // elemIDsToRemove.push_back( e->GetID() );
10046 SMDSAbs_ElementType etyp = e->GetType();
10047 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10050 myLastCreatedElems.Append(newElem);
10051 AddToSameGroups(newElem, e, aMesh);
10052 int aShapeId = e->getshapeId();
10055 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10058 aMesh->RemoveElement(e);
10063 Remove( nodeIDsToRemove, true );
10068 //================================================================================
10070 * \brief Find corresponding nodes in two sets of faces
10071 * \param theSide1 - first face set
10072 * \param theSide2 - second first face
10073 * \param theFirstNode1 - a boundary node of set 1
10074 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10075 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10076 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10077 * \param nReplaceMap - output map of corresponding nodes
10078 * \retval bool - is a success or not
10080 //================================================================================
10083 //#define DEBUG_MATCHING_NODES
10086 SMESH_MeshEditor::Sew_Error
10087 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10088 set<const SMDS_MeshElement*>& theSide2,
10089 const SMDS_MeshNode* theFirstNode1,
10090 const SMDS_MeshNode* theFirstNode2,
10091 const SMDS_MeshNode* theSecondNode1,
10092 const SMDS_MeshNode* theSecondNode2,
10093 TNodeNodeMap & nReplaceMap)
10095 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10097 nReplaceMap.clear();
10098 if ( theFirstNode1 != theFirstNode2 )
10099 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10100 if ( theSecondNode1 != theSecondNode2 )
10101 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10103 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10104 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10106 list< NLink > linkList[2];
10107 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10108 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10110 // loop on links in linkList; find faces by links and append links
10111 // of the found faces to linkList
10112 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10113 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10114 NLink link[] = { *linkIt[0], *linkIt[1] };
10115 if ( linkSet.find( link[0] ) == linkSet.end() )
10118 // by links, find faces in the face sets,
10119 // and find indices of link nodes in the found faces;
10120 // in a face set, there is only one or no face sharing a link
10121 // ---------------------------------------------------------------
10123 const SMDS_MeshElement* face[] = { 0, 0 };
10124 list<const SMDS_MeshNode*> notLinkNodes[2];
10125 //bool reverse[] = { false, false }; // order of notLinkNodes
10127 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10129 const SMDS_MeshNode* n1 = link[iSide].first;
10130 const SMDS_MeshNode* n2 = link[iSide].second;
10131 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10132 set< const SMDS_MeshElement* > facesOfNode1;
10133 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10135 // during a loop of the first node, we find all faces around n1,
10136 // during a loop of the second node, we find one face sharing both n1 and n2
10137 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10138 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10139 while ( fIt->more() ) { // loop on faces sharing a node
10140 const SMDS_MeshElement* f = fIt->next();
10141 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10142 ! facesOfNode1.insert( f ).second ) // f encounters twice
10144 if ( face[ iSide ] ) {
10145 MESSAGE( "2 faces per link " );
10146 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10149 faceSet->erase( f );
10151 // get not link nodes
10152 int nbN = f->NbNodes();
10153 if ( f->IsQuadratic() )
10155 nbNodes[ iSide ] = nbN;
10156 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10157 int i1 = f->GetNodeIndex( n1 );
10158 int i2 = f->GetNodeIndex( n2 );
10159 int iEnd = nbN, iBeg = -1, iDelta = 1;
10160 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10162 std::swap( iEnd, iBeg ); iDelta = -1;
10167 if ( i == iEnd ) i = iBeg + iDelta;
10168 if ( i == i1 ) break;
10169 nodes.push_back ( f->GetNode( i ) );
10175 // check similarity of elements of the sides
10176 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10177 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10178 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10179 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10182 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10186 // set nodes to merge
10187 // -------------------
10189 if ( face[0] && face[1] ) {
10190 if ( nbNodes[0] != nbNodes[1] ) {
10191 MESSAGE("Diff nb of face nodes");
10192 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10194 #ifdef DEBUG_MATCHING_NODES
10195 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10196 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10197 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10199 int nbN = nbNodes[0];
10201 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10202 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10203 for ( int i = 0 ; i < nbN - 2; ++i ) {
10204 #ifdef DEBUG_MATCHING_NODES
10205 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10207 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10211 // add other links of the face 1 to linkList
10212 // -----------------------------------------
10214 const SMDS_MeshElement* f0 = face[0];
10215 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10216 for ( int i = 0; i < nbN; i++ )
10218 const SMDS_MeshNode* n2 = f0->GetNode( i );
10219 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10220 linkSet.insert( SMESH_TLink( n1, n2 ));
10221 if ( !iter_isnew.second ) { // already in a set: no need to process
10222 linkSet.erase( iter_isnew.first );
10224 else // new in set == encountered for the first time: add
10226 #ifdef DEBUG_MATCHING_NODES
10227 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10228 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10230 linkList[0].push_back ( NLink( n1, n2 ));
10231 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10236 } // loop on link lists
10241 //================================================================================
10243 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10244 \param theElems - the list of elements (edges or faces) to be replicated
10245 The nodes for duplication could be found from these elements
10246 \param theNodesNot - list of nodes to NOT replicate
10247 \param theAffectedElems - the list of elements (cells and edges) to which the
10248 replicated nodes should be associated to.
10249 \return TRUE if operation has been completed successfully, FALSE otherwise
10251 //================================================================================
10253 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10254 const TIDSortedElemSet& theNodesNot,
10255 const TIDSortedElemSet& theAffectedElems )
10257 myLastCreatedElems.Clear();
10258 myLastCreatedNodes.Clear();
10260 if ( theElems.size() == 0 )
10263 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10268 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10269 // duplicate elements and nodes
10270 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10271 // replce nodes by duplications
10272 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10276 //================================================================================
10278 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10279 \param theMeshDS - mesh instance
10280 \param theElems - the elements replicated or modified (nodes should be changed)
10281 \param theNodesNot - nodes to NOT replicate
10282 \param theNodeNodeMap - relation of old node to new created node
10283 \param theIsDoubleElem - flag os to replicate element or modify
10284 \return TRUE if operation has been completed successfully, FALSE otherwise
10286 //================================================================================
10288 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10289 const TIDSortedElemSet& theElems,
10290 const TIDSortedElemSet& theNodesNot,
10291 std::map< const SMDS_MeshNode*,
10292 const SMDS_MeshNode* >& theNodeNodeMap,
10293 const bool theIsDoubleElem )
10295 MESSAGE("doubleNodes");
10296 // iterate on through element and duplicate them (by nodes duplication)
10298 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10299 for ( ; elemItr != theElems.end(); ++elemItr )
10301 const SMDS_MeshElement* anElem = *elemItr;
10305 bool isDuplicate = false;
10306 // duplicate nodes to duplicate element
10307 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10308 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10310 while ( anIter->more() )
10313 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10314 SMDS_MeshNode* aNewNode = aCurrNode;
10315 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10316 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10317 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10320 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10321 theNodeNodeMap[ aCurrNode ] = aNewNode;
10322 myLastCreatedNodes.Append( aNewNode );
10324 isDuplicate |= (aCurrNode != aNewNode);
10325 newNodes[ ind++ ] = aNewNode;
10327 if ( !isDuplicate )
10330 if ( theIsDoubleElem )
10331 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10334 MESSAGE("ChangeElementNodes");
10335 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10342 //================================================================================
10344 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10345 \param theNodes - identifiers of nodes to be doubled
10346 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10347 nodes. If list of element identifiers is empty then nodes are doubled but
10348 they not assigned to elements
10349 \return TRUE if operation has been completed successfully, FALSE otherwise
10351 //================================================================================
10353 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10354 const std::list< int >& theListOfModifiedElems )
10356 MESSAGE("DoubleNodes");
10357 myLastCreatedElems.Clear();
10358 myLastCreatedNodes.Clear();
10360 if ( theListOfNodes.size() == 0 )
10363 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10367 // iterate through nodes and duplicate them
10369 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10371 std::list< int >::const_iterator aNodeIter;
10372 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10374 int aCurr = *aNodeIter;
10375 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10381 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10384 anOldNodeToNewNode[ aNode ] = aNewNode;
10385 myLastCreatedNodes.Append( aNewNode );
10389 // Create map of new nodes for modified elements
10391 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10393 std::list< int >::const_iterator anElemIter;
10394 for ( anElemIter = theListOfModifiedElems.begin();
10395 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10397 int aCurr = *anElemIter;
10398 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10402 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10404 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10406 while ( anIter->more() )
10408 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10409 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10411 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10412 aNodeArr[ ind++ ] = aNewNode;
10415 aNodeArr[ ind++ ] = aCurrNode;
10417 anElemToNodes[ anElem ] = aNodeArr;
10420 // Change nodes of elements
10422 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10423 anElemToNodesIter = anElemToNodes.begin();
10424 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10426 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10427 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10430 MESSAGE("ChangeElementNodes");
10431 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10440 //================================================================================
10442 \brief Check if element located inside shape
10443 \return TRUE if IN or ON shape, FALSE otherwise
10445 //================================================================================
10447 template<class Classifier>
10448 bool isInside(const SMDS_MeshElement* theElem,
10449 Classifier& theClassifier,
10450 const double theTol)
10452 gp_XYZ centerXYZ (0, 0, 0);
10453 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10454 while (aNodeItr->more())
10455 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10457 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10458 theClassifier.Perform(aPnt, theTol);
10459 TopAbs_State aState = theClassifier.State();
10460 return (aState == TopAbs_IN || aState == TopAbs_ON );
10463 //================================================================================
10465 * \brief Classifier of the 3D point on the TopoDS_Face
10466 * with interaface suitable for isInside()
10468 //================================================================================
10470 struct _FaceClassifier
10472 Extrema_ExtPS _extremum;
10473 BRepAdaptor_Surface _surface;
10474 TopAbs_State _state;
10476 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10478 _extremum.Initialize( _surface,
10479 _surface.FirstUParameter(), _surface.LastUParameter(),
10480 _surface.FirstVParameter(), _surface.LastVParameter(),
10481 _surface.Tolerance(), _surface.Tolerance() );
10483 void Perform(const gp_Pnt& aPnt, double theTol)
10485 _state = TopAbs_OUT;
10486 _extremum.Perform(aPnt);
10487 if ( _extremum.IsDone() )
10488 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10489 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10491 TopAbs_State State() const
10498 //================================================================================
10500 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10501 \param theElems - group of of elements (edges or faces) to be replicated
10502 \param theNodesNot - group of nodes not to replicate
10503 \param theShape - shape to detect affected elements (element which geometric center
10504 located on or inside shape).
10505 The replicated nodes should be associated to affected elements.
10506 \return TRUE if operation has been completed successfully, FALSE otherwise
10508 //================================================================================
10510 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10511 const TIDSortedElemSet& theNodesNot,
10512 const TopoDS_Shape& theShape )
10514 if ( theShape.IsNull() )
10517 const double aTol = Precision::Confusion();
10518 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10519 auto_ptr<_FaceClassifier> aFaceClassifier;
10520 if ( theShape.ShapeType() == TopAbs_SOLID )
10522 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10523 bsc3d->PerformInfinitePoint(aTol);
10525 else if (theShape.ShapeType() == TopAbs_FACE )
10527 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10530 // iterates on indicated elements and get elements by back references from their nodes
10531 TIDSortedElemSet anAffected;
10532 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10533 for ( ; elemItr != theElems.end(); ++elemItr )
10535 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10539 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10540 while ( nodeItr->more() )
10542 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10543 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10545 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10546 while ( backElemItr->more() )
10548 const SMDS_MeshElement* curElem = backElemItr->next();
10549 if ( curElem && theElems.find(curElem) == theElems.end() &&
10551 isInside( curElem, *bsc3d, aTol ) :
10552 isInside( curElem, *aFaceClassifier, aTol )))
10553 anAffected.insert( curElem );
10557 return DoubleNodes( theElems, theNodesNot, anAffected );
10561 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10562 * The list of groups must describe a partition of the mesh volumes.
10563 * The nodes of the internal faces at the boundaries of the groups are doubled.
10564 * In option, the internal faces are replaced by flat elements.
10565 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10566 * @param theElems - list of groups of volumes, where a group of volume is a set of
10567 * SMDS_MeshElements sorted by Id.
10568 * @param createJointElems - if TRUE, create the elements
10569 * @return TRUE if operation has been completed successfully, FALSE otherwise
10571 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10572 bool createJointElems)
10574 MESSAGE("------------------------------------------------------");
10575 MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10576 MESSAGE("------------------------------------------------------");
10578 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10579 meshDS->BuildDownWardConnectivity(false);
10581 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10583 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10584 // build the list of nodes shared by 2 or more domains, with their domain indexes
10586 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10587 std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
10588 faceDomains.clear();
10589 nodeDomains.clear();
10590 std::map<int,int> emptyMap;
10593 for (int idom = 0; idom < theElems.size(); idom++)
10596 // --- build a map (face to duplicate --> volume to modify)
10597 // with all the faces shared by 2 domains (group of elements)
10598 // and corresponding volume of this domain, for each shared face.
10599 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10601 const TIDSortedElemSet& domain = theElems[idom];
10602 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10603 for (; elemItr != domain.end(); ++elemItr)
10605 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10608 int vtkId = anElem->getVtkId();
10609 int neighborsVtkIds[NBMAXNEIGHBORS];
10610 int downIds[NBMAXNEIGHBORS];
10611 unsigned char downTypes[NBMAXNEIGHBORS];
10612 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10613 for (int n = 0; n < nbNeighbors; n++)
10615 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10616 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10617 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10619 DownIdType face(downIds[n], downTypes[n]);
10620 if (!faceDomains.count(face))
10621 faceDomains[face] = emptyMap; // create an empty entry for face
10622 if (!faceDomains[face].count(idom))
10624 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10631 MESSAGE("Number of shared faces " << faceDomains.size());
10633 // --- for each shared face, get the nodes
10634 // for each node, for each domain of the face, create a clone of the node
10636 std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10637 for( ; itface != faceDomains.end();++itface )
10639 DownIdType face = itface->first;
10640 std::map<int,int> domvol = itface->second;
10641 std::set<int> oldNodes;
10643 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10644 std::set<int>::iterator itn = oldNodes.begin();
10645 for (;itn != oldNodes.end(); ++itn)
10648 if (!nodeDomains.count(oldId))
10649 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10650 std::map<int,int>::iterator itdom = domvol.begin();
10651 for(; itdom != domvol.end(); ++itdom)
10653 int idom = itdom->first;
10654 if ( nodeDomains[oldId].empty() )
10655 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10658 double *coords = grid->GetPoint(oldId);
10659 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10660 int newId = newNode->getVtkId();
10661 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10667 // --- iterate on shared faces (volumes to modify, face to extrude)
10668 // get node id's of the face (id SMDS = id VTK)
10669 // create flat element with old and new nodes if requested
10671 if (createJointElems)
10673 itface = faceDomains.begin();
10674 for( ; itface != faceDomains.end();++itface )
10676 DownIdType face = itface->first;
10677 std::set<int> oldNodes;
10678 std::set<int>::iterator itn;
10680 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10681 std::map<int,int> localClonedNodeIds;
10683 std::map<int,int> domvol = itface->second;
10684 std::map<int,int>::iterator itdom = domvol.begin();
10685 int dom1 = itdom->first;
10686 int vtkVolId = itdom->second;
10688 int dom2 = itdom->first;
10690 localClonedNodeIds.clear();
10691 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10695 if (nodeDomains[oldId].count(dom1))
10696 refid = nodeDomains[oldId][dom1];
10698 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10700 if (nodeDomains[oldId].count(dom2))
10701 newid = nodeDomains[oldId][dom2];
10703 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10704 localClonedNodeIds[oldId] = newid;
10706 meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10710 // --- iterate on shared faces (volumes to modify, face to extrude)
10711 // get node id's of the face
10712 // replace old nodes by new nodes in volumes, and update inverse connectivity
10714 itface = faceDomains.begin();
10715 for( ; itface != faceDomains.end();++itface )
10717 DownIdType face = itface->first;
10718 std::set<int> oldNodes;
10719 std::set<int>::iterator itn;
10721 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10722 std::map<int,int> localClonedNodeIds;
10724 std::map<int,int> domvol = itface->second;
10725 std::map<int,int>::iterator itdom = domvol.begin();
10726 for(; itdom != domvol.end(); ++itdom)
10728 int idom = itdom->first;
10729 int vtkVolId = itdom->second;
10730 localClonedNodeIds.clear();
10731 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10734 if (nodeDomains[oldId].count(idom))
10735 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10737 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10740 grid->BuildLinks();
10742 // TODO replace also old nodes by new nodes in faces and edges
10748 //================================================================================
10750 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10751 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10752 * \return TRUE if operation has been completed successfully, FALSE otherwise
10754 //================================================================================
10756 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10758 // iterates on volume elements and detect all free faces on them
10759 SMESHDS_Mesh* aMesh = GetMeshDS();
10762 //bool res = false;
10763 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10764 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10767 const SMDS_MeshVolume* volume = vIt->next();
10768 SMDS_VolumeTool vTool( volume );
10769 vTool.SetExternalNormal();
10770 const bool isPoly = volume->IsPoly();
10771 const bool isQuad = volume->IsQuadratic();
10772 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10774 if (!vTool.IsFreeFace(iface))
10777 vector<const SMDS_MeshNode *> nodes;
10778 int nbFaceNodes = vTool.NbFaceNodes(iface);
10779 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10781 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10782 nodes.push_back(faceNodes[inode]);
10784 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10785 nodes.push_back(faceNodes[inode]);
10787 // add new face based on volume nodes
10788 if (aMesh->FindFace( nodes ) ) {
10790 continue; // face already exsist
10792 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10796 return ( nbFree==(nbExisted+nbCreated) );
10801 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10803 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10805 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10808 //================================================================================
10810 * \brief Creates missing boundary elements
10811 * \param elements - elements whose boundary is to be checked
10812 * \param dimension - defines type of boundary elements to create
10813 * \param group - a group to store created boundary elements in
10814 * \param targetMesh - a mesh to store created boundary elements in
10815 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10816 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10817 * boundary elements will be copied into the targetMesh
10819 //================================================================================
10821 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10822 Bnd_Dimension dimension,
10823 SMESH_Group* group/*=0*/,
10824 SMESH_Mesh* targetMesh/*=0*/,
10825 bool toCopyElements/*=false*/,
10826 bool toCopyExistingBondary/*=false*/)
10828 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10829 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10830 // hope that all elements are of the same type, do not check them all
10831 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10832 throw SALOME_Exception(LOCALIZED("wrong element type"));
10835 toCopyElements = toCopyExistingBondary = false;
10837 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10838 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10840 SMDS_VolumeTool vTool;
10841 TIDSortedElemSet emptySet, avoidSet;
10844 typedef vector<const SMDS_MeshNode*> TConnectivity;
10846 SMDS_ElemIteratorPtr eIt;
10847 if (elements.empty())
10848 eIt = aMesh->elementsIterator(elemType);
10850 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10852 while (eIt->more())
10854 const SMDS_MeshElement* elem = eIt->next();
10855 const int iQuad = elem->IsQuadratic();
10857 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10858 vector<const SMDS_MeshElement*> presentBndElems;
10859 vector<TConnectivity> missingBndElems;
10860 TConnectivity nodes;
10861 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10863 vTool.SetExternalNormal();
10864 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10866 if (!vTool.IsFreeFace(iface))
10868 int nbFaceNodes = vTool.NbFaceNodes(iface);
10869 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10870 if ( missType == SMDSAbs_Edge ) // boundary edges
10872 nodes.resize( 2+iQuad );
10873 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10875 for ( int j = 0; j < nodes.size(); ++j )
10877 if ( const SMDS_MeshElement* edge =
10878 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10879 presentBndElems.push_back( edge );
10881 missingBndElems.push_back( nodes );
10884 else // boundary face
10887 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10888 nodes.push_back( nn[inode] );
10890 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10891 nodes.push_back( nn[inode] );
10893 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10894 presentBndElems.push_back( f );
10896 missingBndElems.push_back( nodes );
10900 else // elem is a face ------------------------------------------
10902 avoidSet.clear(), avoidSet.insert( elem );
10903 int nbNodes = elem->NbCornerNodes();
10904 nodes.resize( 2 /*+ iQuad*/);
10905 for ( int i = 0; i < nbNodes; i++ )
10907 nodes[0] = elem->GetNode(i);
10908 nodes[1] = elem->GetNode((i+1)%nbNodes);
10909 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10910 continue; // not free link
10913 //nodes[2] = elem->GetNode( i + nbNodes );
10914 if ( const SMDS_MeshElement* edge =
10915 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10916 presentBndElems.push_back( edge );
10918 missingBndElems.push_back( nodes );
10922 // 2. Add missing boundary elements
10923 if ( targetMesh != myMesh )
10924 // instead of making a map of nodes in this mesh and targetMesh,
10925 // we create nodes with same IDs. We can renumber them later, if needed
10926 for ( int i = 0; i < missingBndElems.size(); ++i )
10928 TConnectivity& srcNodes = missingBndElems[i];
10929 TConnectivity nodes( srcNodes.size() );
10930 for ( inode = 0; inode < nodes.size(); ++inode )
10931 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10932 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10935 for ( int i = 0; i < missingBndElems.size(); ++i )
10937 TConnectivity& nodes = missingBndElems[i];
10938 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10941 // 3. Copy present boundary elements
10942 if ( toCopyExistingBondary )
10943 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10945 const SMDS_MeshElement* e = presentBndElems[i];
10946 TConnectivity nodes( e->NbNodes() );
10947 for ( inode = 0; inode < nodes.size(); ++inode )
10948 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10949 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10950 // leave only missing elements in tgtEditor.myLastCreatedElems
10951 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10953 } // loop on given elements
10955 // 4. Fill group with missing boundary elements
10958 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10959 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10960 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10962 tgtEditor.myLastCreatedElems.Clear();
10964 // 5. Copy given elements
10965 if ( toCopyElements )
10967 if (elements.empty())
10968 eIt = aMesh->elementsIterator(elemType);
10970 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10971 while (eIt->more())
10973 const SMDS_MeshElement* elem = eIt->next();
10974 TConnectivity nodes( elem->NbNodes() );
10975 for ( inode = 0; inode < nodes.size(); ++inode )
10976 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10977 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10979 tgtEditor.myLastCreatedElems.Clear();