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() ) {
5313 MESSAGE("gp_PntMirror");
5315 groupPostfix = "mirrored";
5318 MESSAGE("gp_Ax1Mirror");
5319 groupPostfix = "mirrored";
5322 MESSAGE("gp_Ax2Mirror");
5324 groupPostfix = "mirrored";
5327 MESSAGE("gp_Rotation");
5328 groupPostfix = "rotated";
5330 case gp_Translation:
5331 MESSAGE("gp_Translation");
5332 groupPostfix = "translated";
5335 MESSAGE("gp_Scale");
5336 groupPostfix = "scaled";
5338 case gp_CompoundTrsf: // different scale by axis
5339 MESSAGE("gp_CompoundTrsf");
5340 groupPostfix = "scaled";
5344 needReverse = false;
5345 groupPostfix = "transformed";
5348 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5349 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5350 SMESHDS_Mesh* aMesh = GetMeshDS();
5353 // map old node to new one
5354 TNodeNodeMap nodeMap;
5356 // elements sharing moved nodes; those of them which have all
5357 // nodes mirrored but are not in theElems are to be reversed
5358 TIDSortedElemSet inverseElemSet;
5360 // source elements for each generated one
5361 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5363 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5364 TIDSortedElemSet orphanNode;
5366 if ( theElems.empty() ) // transform the whole mesh
5369 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5370 while ( eIt->more() ) theElems.insert( eIt->next() );
5372 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5373 while ( nIt->more() )
5375 const SMDS_MeshNode* node = nIt->next();
5376 if ( node->NbInverseElements() == 0)
5377 orphanNode.insert( node );
5381 // loop on elements to transform nodes : first orphan nodes then elems
5382 TIDSortedElemSet::iterator itElem;
5383 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5384 for (int i=0; i<2; i++)
5385 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5386 const SMDS_MeshElement* elem = *itElem;
5390 // loop on elem nodes
5391 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5392 while ( itN->more() ) {
5394 const SMDS_MeshNode* node = cast2Node( itN->next() );
5395 // check if a node has been already transformed
5396 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5397 nodeMap.insert( make_pair ( node, node ));
5398 if ( !n2n_isnew.second )
5402 coord[0] = node->X();
5403 coord[1] = node->Y();
5404 coord[2] = node->Z();
5405 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5406 if ( theTargetMesh ) {
5407 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5408 n2n_isnew.first->second = newNode;
5409 myLastCreatedNodes.Append(newNode);
5410 srcNodes.Append( node );
5412 else if ( theCopy ) {
5413 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5414 n2n_isnew.first->second = newNode;
5415 myLastCreatedNodes.Append(newNode);
5416 srcNodes.Append( node );
5419 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5420 // node position on shape becomes invalid
5421 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5422 ( SMDS_SpacePosition::originSpacePosition() );
5425 // keep inverse elements
5426 if ( !theCopy && !theTargetMesh && needReverse ) {
5427 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5428 while ( invElemIt->more() ) {
5429 const SMDS_MeshElement* iel = invElemIt->next();
5430 inverseElemSet.insert( iel );
5436 // either create new elements or reverse mirrored ones
5437 if ( !theCopy && !needReverse && !theTargetMesh )
5440 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5441 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5442 theElems.insert( *invElemIt );
5444 // replicate or reverse elements
5445 // TODO revoir ordre reverse vtk
5447 REV_TETRA = 0, // = nbNodes - 4
5448 REV_PYRAMID = 1, // = nbNodes - 4
5449 REV_PENTA = 2, // = nbNodes - 4
5451 REV_HEXA = 4, // = nbNodes - 4
5455 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5456 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5457 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5458 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5459 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5460 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5463 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5465 const SMDS_MeshElement* elem = *itElem;
5466 if ( !elem || elem->GetType() == SMDSAbs_Node )
5469 int nbNodes = elem->NbNodes();
5470 int elemType = elem->GetType();
5472 if (elem->IsPoly()) {
5473 // Polygon or Polyhedral Volume
5474 switch ( elemType ) {
5477 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5479 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5480 while (itN->more()) {
5481 const SMDS_MeshNode* node =
5482 static_cast<const SMDS_MeshNode*>(itN->next());
5483 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5484 if (nodeMapIt == nodeMap.end())
5485 break; // not all nodes transformed
5487 // reverse mirrored faces and volumes
5488 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5490 poly_nodes[iNode] = (*nodeMapIt).second;
5494 if ( iNode != nbNodes )
5495 continue; // not all nodes transformed
5497 if ( theTargetMesh ) {
5498 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5499 srcElems.Append( elem );
5501 else if ( theCopy ) {
5502 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5503 srcElems.Append( elem );
5506 aMesh->ChangePolygonNodes(elem, poly_nodes);
5510 case SMDSAbs_Volume:
5512 // ATTENTION: Reversing is not yet done!!!
5513 const SMDS_VtkVolume* aPolyedre =
5514 dynamic_cast<const SMDS_VtkVolume*>( elem );
5516 MESSAGE("Warning: bad volumic element");
5520 vector<const SMDS_MeshNode*> poly_nodes;
5521 vector<int> quantities;
5523 bool allTransformed = true;
5524 int nbFaces = aPolyedre->NbFaces();
5525 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5526 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5527 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5528 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5529 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5530 if (nodeMapIt == nodeMap.end()) {
5531 allTransformed = false; // not all nodes transformed
5533 poly_nodes.push_back((*nodeMapIt).second);
5536 quantities.push_back(nbFaceNodes);
5538 if ( !allTransformed )
5539 continue; // not all nodes transformed
5541 if ( theTargetMesh ) {
5542 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5543 srcElems.Append( elem );
5545 else if ( theCopy ) {
5546 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5547 srcElems.Append( elem );
5550 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5560 int* i = index[ FORWARD ];
5561 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5562 if ( elemType == SMDSAbs_Face )
5563 i = index[ REV_FACE ];
5565 i = index[ nbNodes - 4 ];
5567 if(elem->IsQuadratic()) {
5568 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5571 if(nbNodes==3) { // quadratic edge
5572 static int anIds[] = {1,0,2};
5575 else if(nbNodes==6) { // quadratic triangle
5576 static int anIds[] = {0,2,1,5,4,3};
5579 else if(nbNodes==8) { // quadratic quadrangle
5580 static int anIds[] = {0,3,2,1,7,6,5,4};
5583 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5584 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5587 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5588 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5591 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5592 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5595 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5596 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5602 // find transformed nodes
5603 vector<const SMDS_MeshNode*> nodes(nbNodes);
5605 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5606 while ( itN->more() ) {
5607 const SMDS_MeshNode* node =
5608 static_cast<const SMDS_MeshNode*>( itN->next() );
5609 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5610 if ( nodeMapIt == nodeMap.end() )
5611 break; // not all nodes transformed
5612 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5614 if ( iNode != nbNodes )
5615 continue; // not all nodes transformed
5617 if ( theTargetMesh ) {
5618 if ( SMDS_MeshElement* copy =
5619 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5620 myLastCreatedElems.Append( copy );
5621 srcElems.Append( elem );
5624 else if ( theCopy ) {
5625 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5626 srcElems.Append( elem );
5629 // reverse element as it was reversed by transformation
5631 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5635 PGroupIDs newGroupIDs;
5637 if ( theMakeGroups && theCopy ||
5638 theMakeGroups && theTargetMesh )
5639 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5645 ////=======================================================================
5646 ////function : Scale
5648 ////=======================================================================
5650 //SMESH_MeshEditor::PGroupIDs
5651 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5652 // const gp_Pnt& thePoint,
5653 // const std::list<double>& theScaleFact,
5654 // const bool theCopy,
5655 // const bool theMakeGroups,
5656 // SMESH_Mesh* theTargetMesh)
5658 // MESSAGE("Scale");
5659 // myLastCreatedElems.Clear();
5660 // myLastCreatedNodes.Clear();
5662 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5663 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5664 // SMESHDS_Mesh* aMesh = GetMeshDS();
5666 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5667 // std::list<double>::const_iterator itS = theScaleFact.begin();
5669 // if(theScaleFact.size()==1) {
5673 // if(theScaleFact.size()==2) {
5678 // if(theScaleFact.size()>2) {
5685 // // map old node to new one
5686 // TNodeNodeMap nodeMap;
5688 // // elements sharing moved nodes; those of them which have all
5689 // // nodes mirrored but are not in theElems are to be reversed
5690 // TIDSortedElemSet inverseElemSet;
5692 // // source elements for each generated one
5693 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5695 // // loop on theElems
5696 // TIDSortedElemSet::iterator itElem;
5697 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5698 // const SMDS_MeshElement* elem = *itElem;
5702 // // loop on elem nodes
5703 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5704 // while ( itN->more() ) {
5706 // // check if a node has been already transformed
5707 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5708 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5709 // nodeMap.insert( make_pair ( node, node ));
5710 // if ( !n2n_isnew.second )
5713 // //double coord[3];
5714 // //coord[0] = node->X();
5715 // //coord[1] = node->Y();
5716 // //coord[2] = node->Z();
5717 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5718 // double dx = (node->X() - thePoint.X()) * scaleX;
5719 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5720 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5721 // if ( theTargetMesh ) {
5722 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5723 // const SMDS_MeshNode * newNode =
5724 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5725 // n2n_isnew.first->second = newNode;
5726 // myLastCreatedNodes.Append(newNode);
5727 // srcNodes.Append( node );
5729 // else if ( theCopy ) {
5730 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5731 // const SMDS_MeshNode * newNode =
5732 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5733 // n2n_isnew.first->second = newNode;
5734 // myLastCreatedNodes.Append(newNode);
5735 // srcNodes.Append( node );
5738 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5739 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5740 // // node position on shape becomes invalid
5741 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5742 // ( SMDS_SpacePosition::originSpacePosition() );
5745 // // keep inverse elements
5746 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5747 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5748 // // while ( invElemIt->more() ) {
5749 // // const SMDS_MeshElement* iel = invElemIt->next();
5750 // // inverseElemSet.insert( iel );
5756 // // either create new elements or reverse mirrored ones
5757 // //if ( !theCopy && !needReverse && !theTargetMesh )
5758 // if ( !theCopy && !theTargetMesh )
5759 // return PGroupIDs();
5761 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5762 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5763 // theElems.insert( *invElemIt );
5765 // // replicate or reverse elements
5768 // REV_TETRA = 0, // = nbNodes - 4
5769 // REV_PYRAMID = 1, // = nbNodes - 4
5770 // REV_PENTA = 2, // = nbNodes - 4
5772 // REV_HEXA = 4, // = nbNodes - 4
5775 // int index[][8] = {
5776 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5777 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5778 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5779 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5780 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5781 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5784 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5786 // const SMDS_MeshElement* elem = *itElem;
5787 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5790 // int nbNodes = elem->NbNodes();
5791 // int elemType = elem->GetType();
5793 // if (elem->IsPoly()) {
5794 // // Polygon or Polyhedral Volume
5795 // switch ( elemType ) {
5796 // case SMDSAbs_Face:
5798 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5800 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5801 // while (itN->more()) {
5802 // const SMDS_MeshNode* node =
5803 // static_cast<const SMDS_MeshNode*>(itN->next());
5804 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5805 // if (nodeMapIt == nodeMap.end())
5806 // break; // not all nodes transformed
5807 // //if (needReverse) {
5808 // // // reverse mirrored faces and volumes
5809 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5811 // poly_nodes[iNode] = (*nodeMapIt).second;
5815 // if ( iNode != nbNodes )
5816 // continue; // not all nodes transformed
5818 // if ( theTargetMesh ) {
5819 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5820 // srcElems.Append( elem );
5822 // else if ( theCopy ) {
5823 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5824 // srcElems.Append( elem );
5827 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5831 // case SMDSAbs_Volume:
5833 // // ATTENTION: Reversing is not yet done!!!
5834 // const SMDS_VtkVolume* aPolyedre =
5835 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5836 // if (!aPolyedre) {
5837 // MESSAGE("Warning: bad volumic element");
5841 // vector<const SMDS_MeshNode*> poly_nodes;
5842 // vector<int> quantities;
5844 // bool allTransformed = true;
5845 // int nbFaces = aPolyedre->NbFaces();
5846 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5847 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5848 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5849 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5850 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5851 // if (nodeMapIt == nodeMap.end()) {
5852 // allTransformed = false; // not all nodes transformed
5854 // poly_nodes.push_back((*nodeMapIt).second);
5857 // quantities.push_back(nbFaceNodes);
5859 // if ( !allTransformed )
5860 // continue; // not all nodes transformed
5862 // if ( theTargetMesh ) {
5863 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5864 // srcElems.Append( elem );
5866 // else if ( theCopy ) {
5867 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5868 // srcElems.Append( elem );
5871 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5880 // // Regular elements
5881 // int* i = index[ FORWARD ];
5882 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5883 // // if ( elemType == SMDSAbs_Face )
5884 // // i = index[ REV_FACE ];
5886 // // i = index[ nbNodes - 4 ];
5888 // if(elem->IsQuadratic()) {
5889 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5891 // //if(needReverse) {
5892 // // if(nbNodes==3) { // quadratic edge
5893 // // static int anIds[] = {1,0,2};
5896 // // else if(nbNodes==6) { // quadratic triangle
5897 // // static int anIds[] = {0,2,1,5,4,3};
5900 // // else if(nbNodes==8) { // quadratic quadrangle
5901 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5904 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5905 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5908 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5909 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5912 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5913 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5916 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5917 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5923 // // find transformed nodes
5924 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5926 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5927 // while ( itN->more() ) {
5928 // const SMDS_MeshNode* node =
5929 // static_cast<const SMDS_MeshNode*>( itN->next() );
5930 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5931 // if ( nodeMapIt == nodeMap.end() )
5932 // break; // not all nodes transformed
5933 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5935 // if ( iNode != nbNodes )
5936 // continue; // not all nodes transformed
5938 // if ( theTargetMesh ) {
5939 // if ( SMDS_MeshElement* copy =
5940 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5941 // myLastCreatedElems.Append( copy );
5942 // srcElems.Append( elem );
5945 // else if ( theCopy ) {
5946 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5947 // myLastCreatedElems.Append( copy );
5948 // srcElems.Append( elem );
5952 // // reverse element as it was reversed by transformation
5953 // if ( nbNodes > 2 )
5954 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5958 // PGroupIDs newGroupIDs;
5960 // if ( theMakeGroups && theCopy ||
5961 // theMakeGroups && theTargetMesh ) {
5962 // string groupPostfix = "scaled";
5963 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5966 // return newGroupIDs;
5970 //=======================================================================
5972 * \brief Create groups of elements made during transformation
5973 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5974 * \param elemGens - elements making corresponding myLastCreatedElems
5975 * \param postfix - to append to names of new groups
5977 //=======================================================================
5979 SMESH_MeshEditor::PGroupIDs
5980 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5981 const SMESH_SequenceOfElemPtr& elemGens,
5982 const std::string& postfix,
5983 SMESH_Mesh* targetMesh)
5985 PGroupIDs newGroupIDs( new list<int> );
5986 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5988 // Sort existing groups by types and collect their names
5990 // to store an old group and a generated new one
5991 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5992 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5994 set< string > groupNames;
5996 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5997 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5998 while ( groupIt->more() ) {
5999 SMESH_Group * group = groupIt->next();
6000 if ( !group ) continue;
6001 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6002 if ( !groupDS || groupDS->IsEmpty() ) continue;
6003 groupNames.insert( group->GetName() );
6004 groupDS->SetStoreName( group->GetName() );
6005 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6010 // loop on nodes and elements
6011 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6013 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6014 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6015 if ( gens.Length() != elems.Length() )
6016 throw SALOME_Exception(LOCALIZED("invalid args"));
6018 // loop on created elements
6019 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6021 const SMDS_MeshElement* sourceElem = gens( iElem );
6022 if ( !sourceElem ) {
6023 MESSAGE("generateGroups(): NULL source element");
6026 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6027 if ( groupsOldNew.empty() ) {
6028 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6029 ++iElem; // skip all elements made by sourceElem
6032 // collect all elements made by sourceElem
6033 list< const SMDS_MeshElement* > resultElems;
6034 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6035 if ( resElem != sourceElem )
6036 resultElems.push_back( resElem );
6037 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6038 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6039 if ( resElem != sourceElem )
6040 resultElems.push_back( resElem );
6041 // do not generate element groups from node ones
6042 if ( sourceElem->GetType() == SMDSAbs_Node &&
6043 elems( iElem )->GetType() != SMDSAbs_Node )
6046 // add resultElems to groups made by ones the sourceElem belongs to
6047 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6048 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6050 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6051 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6053 SMDS_MeshGroup* & newGroup = gOldNew->second;
6054 if ( !newGroup )// create a new group
6057 string name = oldGroup->GetStoreName();
6058 if ( !targetMesh ) {
6062 while ( !groupNames.insert( name ).second ) // name exists
6068 TCollection_AsciiString nbStr(nb+1);
6069 name.resize( name.rfind('_')+1 );
6070 name += nbStr.ToCString();
6077 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6079 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6080 newGroup = & groupDS->SMDSGroup();
6081 newGroupIDs->push_back( id );
6084 // fill in a new group
6085 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6086 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6087 newGroup->Add( *resElemIt );
6090 } // loop on created elements
6091 }// loop on nodes and elements
6096 //================================================================================
6098 * \brief Return list of group of nodes close to each other within theTolerance
6099 * Search among theNodes or in the whole mesh if theNodes is empty using
6100 * an Octree algorithm
6102 //================================================================================
6104 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6105 const double theTolerance,
6106 TListOfListOfNodes & theGroupsOfNodes)
6108 myLastCreatedElems.Clear();
6109 myLastCreatedNodes.Clear();
6111 if ( theNodes.empty() )
6112 { // get all nodes in the mesh
6113 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6114 while ( nIt->more() )
6115 theNodes.insert( theNodes.end(),nIt->next());
6118 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6122 //=======================================================================
6124 * \brief Implementation of search for the node closest to point
6126 //=======================================================================
6128 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6130 //---------------------------------------------------------------------
6132 * \brief Constructor
6134 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6136 myMesh = ( SMESHDS_Mesh* ) theMesh;
6138 TIDSortedNodeSet nodes;
6140 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6141 while ( nIt->more() )
6142 nodes.insert( nodes.end(), nIt->next() );
6144 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6146 // get max size of a leaf box
6147 SMESH_OctreeNode* tree = myOctreeNode;
6148 while ( !tree->isLeaf() )
6150 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6154 myHalfLeafSize = tree->maxSize() / 2.;
6157 //---------------------------------------------------------------------
6159 * \brief Move node and update myOctreeNode accordingly
6161 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6163 myOctreeNode->UpdateByMoveNode( node, toPnt );
6164 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6167 //---------------------------------------------------------------------
6169 * \brief Do it's job
6171 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6173 map<double, const SMDS_MeshNode*> dist2Nodes;
6174 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6175 if ( !dist2Nodes.empty() )
6176 return dist2Nodes.begin()->second;
6177 list<const SMDS_MeshNode*> nodes;
6178 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6180 double minSqDist = DBL_MAX;
6181 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6183 // sort leafs by their distance from thePnt
6184 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6185 TDistTreeMap treeMap;
6186 list< SMESH_OctreeNode* > treeList;
6187 list< SMESH_OctreeNode* >::iterator trIt;
6188 treeList.push_back( myOctreeNode );
6190 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6191 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6192 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6194 SMESH_OctreeNode* tree = *trIt;
6195 if ( !tree->isLeaf() ) // put children to the queue
6197 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6198 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6199 while ( cIt->more() )
6200 treeList.push_back( cIt->next() );
6202 else if ( tree->NbNodes() ) // put a tree to the treeMap
6204 const Bnd_B3d& box = tree->getBox();
6205 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6206 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6207 if ( !it_in.second ) // not unique distance to box center
6208 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6211 // find distance after which there is no sense to check tree's
6212 double sqLimit = DBL_MAX;
6213 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6214 if ( treeMap.size() > 5 ) {
6215 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6216 const Bnd_B3d& box = closestTree->getBox();
6217 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6218 sqLimit = limit * limit;
6220 // get all nodes from trees
6221 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6222 if ( sqDist_tree->first > sqLimit )
6224 SMESH_OctreeNode* tree = sqDist_tree->second;
6225 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6228 // find closest among nodes
6229 minSqDist = DBL_MAX;
6230 const SMDS_MeshNode* closestNode = 0;
6231 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6232 for ( ; nIt != nodes.end(); ++nIt ) {
6233 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6234 if ( minSqDist > sqDist ) {
6242 //---------------------------------------------------------------------
6246 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6248 //---------------------------------------------------------------------
6250 * \brief Return the node tree
6252 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6255 SMESH_OctreeNode* myOctreeNode;
6256 SMESHDS_Mesh* myMesh;
6257 double myHalfLeafSize; // max size of a leaf box
6260 //=======================================================================
6262 * \brief Return SMESH_NodeSearcher
6264 //=======================================================================
6266 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6268 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6271 // ========================================================================
6272 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6274 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6275 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6276 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6278 //=======================================================================
6280 * \brief Octal tree of bounding boxes of elements
6282 //=======================================================================
6284 class ElementBndBoxTree : public SMESH_Octree
6288 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
6289 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6290 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6291 ~ElementBndBoxTree();
6294 ElementBndBoxTree() {}
6295 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6296 void buildChildrenData();
6297 Bnd_B3d* buildRootBox();
6299 //!< Bounding box of element
6300 struct ElementBox : public Bnd_B3d
6302 const SMDS_MeshElement* _element;
6303 int _refCount; // an ElementBox can be included in several tree branches
6304 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6306 vector< ElementBox* > _elements;
6309 //================================================================================
6311 * \brief ElementBndBoxTree creation
6313 //================================================================================
6315 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
6316 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6318 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6319 _elements.reserve( nbElems );
6321 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6322 while ( elemIt->more() )
6323 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6325 if ( _elements.size() > MaxNbElemsInLeaf )
6331 //================================================================================
6335 //================================================================================
6337 ElementBndBoxTree::~ElementBndBoxTree()
6339 for ( int i = 0; i < _elements.size(); ++i )
6340 if ( --_elements[i]->_refCount <= 0 )
6341 delete _elements[i];
6344 //================================================================================
6346 * \brief Return the maximal box
6348 //================================================================================
6350 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6352 Bnd_B3d* box = new Bnd_B3d;
6353 for ( int i = 0; i < _elements.size(); ++i )
6354 box->Add( *_elements[i] );
6358 //================================================================================
6360 * \brief Redistrubute element boxes among children
6362 //================================================================================
6364 void ElementBndBoxTree::buildChildrenData()
6366 for ( int i = 0; i < _elements.size(); ++i )
6368 for (int j = 0; j < 8; j++)
6370 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6372 _elements[i]->_refCount++;
6373 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6376 _elements[i]->_refCount--;
6380 for (int j = 0; j < 8; j++)
6382 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6383 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6384 child->myIsLeaf = true;
6386 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6387 child->_elements.resize( child->_elements.size() ); // compact
6391 //================================================================================
6393 * \brief Return elements which can include the point
6395 //================================================================================
6397 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6398 TIDSortedElemSet& foundElems)
6400 if ( level() && getBox().IsOut( point.XYZ() ))
6405 for ( int i = 0; i < _elements.size(); ++i )
6406 if ( !_elements[i]->IsOut( point.XYZ() ))
6407 foundElems.insert( _elements[i]->_element );
6411 for (int i = 0; i < 8; i++)
6412 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6416 //================================================================================
6418 * \brief Return elements which can be intersected by the line
6420 //================================================================================
6422 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6423 TIDSortedElemSet& foundElems)
6425 if ( level() && getBox().IsOut( line ))
6430 for ( int i = 0; i < _elements.size(); ++i )
6431 if ( !_elements[i]->IsOut( line ))
6432 foundElems.insert( _elements[i]->_element );
6436 for (int i = 0; i < 8; i++)
6437 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6441 //================================================================================
6443 * \brief Construct the element box
6445 //================================================================================
6447 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6451 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6452 while ( nIt->more() )
6453 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6454 Enlarge( tolerance );
6459 //=======================================================================
6461 * \brief Implementation of search for the elements by point and
6462 * of classification of point in 2D mesh
6464 //=======================================================================
6466 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6468 SMESHDS_Mesh* _mesh;
6469 ElementBndBoxTree* _ebbTree;
6470 SMESH_NodeSearcherImpl* _nodeSearcher;
6471 SMDSAbs_ElementType _elementType;
6473 bool _outerFacesFound;
6474 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6476 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6477 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6478 ~SMESH_ElementSearcherImpl()
6480 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6481 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6483 virtual int FindElementsByPoint(const gp_Pnt& point,
6484 SMDSAbs_ElementType type,
6485 vector< const SMDS_MeshElement* >& foundElements);
6486 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6488 void GetElementsNearLine( const gp_Ax1& line,
6489 SMDSAbs_ElementType type,
6490 vector< const SMDS_MeshElement* >& foundElems);
6491 double getTolerance();
6492 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6493 const double tolerance, double & param);
6494 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6495 bool isOuterBoundary(const SMDS_MeshElement* face) const
6497 return _outerFaces.empty() || _outerFaces.count(face);
6499 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6501 const SMDS_MeshElement* _face;
6503 bool _coincides; //!< the line lays in face plane
6504 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6505 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6507 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6510 TIDSortedElemSet _faces;
6511 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6512 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6516 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6518 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6519 << ", _coincides="<<i._coincides << ")";
6522 //=======================================================================
6524 * \brief define tolerance for search
6526 //=======================================================================
6528 double SMESH_ElementSearcherImpl::getTolerance()
6530 if ( _tolerance < 0 )
6532 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6535 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6537 double boxSize = _nodeSearcher->getTree()->maxSize();
6538 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6540 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6542 double boxSize = _ebbTree->maxSize();
6543 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6545 if ( _tolerance == 0 )
6547 // define tolerance by size of a most complex element
6548 int complexType = SMDSAbs_Volume;
6549 while ( complexType > SMDSAbs_All &&
6550 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6552 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6554 if ( complexType == int( SMDSAbs_Node ))
6556 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6558 if ( meshInfo.NbNodes() > 2 )
6559 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6563 SMDS_ElemIteratorPtr elemIt =
6564 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6565 const SMDS_MeshElement* elem = elemIt->next();
6566 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6567 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6568 while ( nodeIt->more() )
6570 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6571 elemSize = max( dist, elemSize );
6574 _tolerance = 1e-4 * elemSize;
6580 //================================================================================
6582 * \brief Find intersection of the line and an edge of face and return parameter on line
6584 //================================================================================
6586 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6587 const SMDS_MeshElement* face,
6594 GeomAPI_ExtremaCurveCurve anExtCC;
6595 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6597 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6598 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6600 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6601 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6602 anExtCC.Init( lineCurve, edge);
6603 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6605 Quantity_Parameter pl, pe;
6606 anExtCC.LowerDistanceParameters( pl, pe );
6608 if ( ++nbInts == 2 )
6612 if ( nbInts > 0 ) param /= nbInts;
6615 //================================================================================
6617 * \brief Find all faces belonging to the outer boundary of mesh
6619 //================================================================================
6621 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6623 if ( _outerFacesFound ) return;
6625 // Collect all outer faces by passing from one outer face to another via their links
6626 // and BTW find out if there are internal faces at all.
6628 // checked links and links where outer boundary meets internal one
6629 set< SMESH_TLink > visitedLinks, seamLinks;
6631 // links to treat with already visited faces sharing them
6632 list < TFaceLink > startLinks;
6634 // load startLinks with the first outerFace
6635 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6636 _outerFaces.insert( outerFace );
6638 TIDSortedElemSet emptySet;
6639 while ( !startLinks.empty() )
6641 const SMESH_TLink& link = startLinks.front()._link;
6642 TIDSortedElemSet& faces = startLinks.front()._faces;
6644 outerFace = *faces.begin();
6645 // find other faces sharing the link
6646 const SMDS_MeshElement* f;
6647 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6650 // select another outer face among the found
6651 const SMDS_MeshElement* outerFace2 = 0;
6652 if ( faces.size() == 2 )
6654 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6656 else if ( faces.size() > 2 )
6658 seamLinks.insert( link );
6660 // link direction within the outerFace
6661 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6662 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6663 int i1 = outerFace->GetNodeIndex( link.node1() );
6664 int i2 = outerFace->GetNodeIndex( link.node2() );
6665 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6666 if ( rev ) n1n2.Reverse();
6668 gp_XYZ ofNorm, fNorm;
6669 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6671 // direction from the link inside outerFace
6672 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6673 // sort all other faces by angle with the dirInOF
6674 map< double, const SMDS_MeshElement* > angle2Face;
6675 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6676 for ( ; face != faces.end(); ++face )
6678 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6680 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6681 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6682 if ( angle < 0 ) angle += 2*PI;
6683 angle2Face.insert( make_pair( angle, *face ));
6685 if ( !angle2Face.empty() )
6686 outerFace2 = angle2Face.begin()->second;
6689 // store the found outer face and add its links to continue seaching from
6692 _outerFaces.insert( outerFace );
6693 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6694 for ( int i = 0; i < nbNodes; ++i )
6696 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6697 if ( visitedLinks.insert( link2 ).second )
6698 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6701 startLinks.pop_front();
6703 _outerFacesFound = true;
6705 if ( !seamLinks.empty() )
6707 // There are internal boundaries touching the outher one,
6708 // find all faces of internal boundaries in order to find
6709 // faces of boundaries of holes, if any.
6714 _outerFaces.clear();
6718 //=======================================================================
6720 * \brief Find elements of given type where the given point is IN or ON.
6721 * Returns nb of found elements and elements them-selves.
6723 * 'ALL' type means elements of any type excluding nodes and 0D elements
6725 //=======================================================================
6727 int SMESH_ElementSearcherImpl::
6728 FindElementsByPoint(const gp_Pnt& point,
6729 SMDSAbs_ElementType type,
6730 vector< const SMDS_MeshElement* >& foundElements)
6732 foundElements.clear();
6734 double tolerance = getTolerance();
6736 // =================================================================================
6737 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6739 if ( !_nodeSearcher )
6740 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6742 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6743 if ( !closeNode ) return foundElements.size();
6745 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6746 return foundElements.size(); // to far from any node
6748 if ( type == SMDSAbs_Node )
6750 foundElements.push_back( closeNode );
6754 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6755 while ( elemIt->more() )
6756 foundElements.push_back( elemIt->next() );
6759 // =================================================================================
6760 else // elements more complex than 0D
6762 if ( !_ebbTree || _elementType != type )
6764 if ( _ebbTree ) delete _ebbTree;
6765 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6767 TIDSortedElemSet suspectElems;
6768 _ebbTree->getElementsNearPoint( point, suspectElems );
6769 TIDSortedElemSet::iterator elem = suspectElems.begin();
6770 for ( ; elem != suspectElems.end(); ++elem )
6771 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6772 foundElements.push_back( *elem );
6774 return foundElements.size();
6777 //================================================================================
6779 * \brief Classify the given point in the closed 2D mesh
6781 //================================================================================
6783 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6785 double tolerance = getTolerance();
6786 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6788 if ( _ebbTree ) delete _ebbTree;
6789 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6791 // Algo: analyse transition of a line starting at the point through mesh boundary;
6792 // try three lines parallel to axis of the coordinate system and perform rough
6793 // analysis. If solution is not clear perform thorough analysis.
6795 const int nbAxes = 3;
6796 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6797 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6798 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6799 multimap< int, int > nbInt2Axis; // to find the simplest case
6800 for ( int axis = 0; axis < nbAxes; ++axis )
6802 gp_Ax1 lineAxis( point, axisDir[axis]);
6803 gp_Lin line ( lineAxis );
6805 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6806 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6808 // Intersect faces with the line
6810 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6811 TIDSortedElemSet::iterator face = suspectFaces.begin();
6812 for ( ; face != suspectFaces.end(); ++face )
6816 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6817 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6819 // perform intersection
6820 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6821 if ( !intersection.IsDone() )
6823 if ( intersection.IsInQuadric() )
6825 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6827 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6829 gp_Pnt intersectionPoint = intersection.Point(1);
6830 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6831 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6834 // Analyse intersections roughly
6836 int nbInter = u2inters.size();
6840 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6841 if ( nbInter == 1 ) // not closed mesh
6842 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6844 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6847 if ( (f<0) == (l<0) )
6850 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6851 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6852 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6855 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6857 if ( _outerFacesFound ) break; // pass to thorough analysis
6859 } // three attempts - loop on CS axes
6861 // Analyse intersections thoroughly.
6862 // We make two loops maximum, on the first one we only exclude touching intersections,
6863 // on the second, if situation is still unclear, we gather and use information on
6864 // position of faces (internal or outer). If faces position is already gathered,
6865 // we make the second loop right away.
6867 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6869 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6870 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6872 int axis = nb_axis->second;
6873 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6875 gp_Ax1 lineAxis( point, axisDir[axis]);
6876 gp_Lin line ( lineAxis );
6878 // add tangent intersections to u2inters
6880 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6881 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6882 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6883 u2inters.insert(make_pair( param, *tgtInt ));
6884 tangentInters[ axis ].clear();
6886 // Count intersections before and after the point excluding touching ones.
6887 // If hasPositionInfo we count intersections of outer boundary only
6889 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6890 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6891 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6892 bool ok = ! u_int1->second._coincides;
6893 while ( ok && u_int1 != u2inters.end() )
6895 double u = u_int1->first;
6896 bool touchingInt = false;
6897 if ( ++u_int2 != u2inters.end() )
6899 // skip intersections at the same point (if the line passes through edge or node)
6901 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6907 // skip tangent intersections
6909 const SMDS_MeshElement* prevFace = u_int1->second._face;
6910 while ( ok && u_int2->second._coincides )
6912 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6918 ok = ( u_int2 != u2inters.end() );
6923 // skip intersections at the same point after tangent intersections
6926 double u2 = u_int2->first;
6928 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6934 // decide if we skipped a touching intersection
6935 if ( nbSamePnt + nbTgt > 0 )
6937 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6938 map< double, TInters >::iterator u_int = u_int1;
6939 for ( ; u_int != u_int2; ++u_int )
6941 if ( u_int->second._coincides ) continue;
6942 double dot = u_int->second._faceNorm * line.Direction();
6943 if ( dot > maxDot ) maxDot = dot;
6944 if ( dot < minDot ) minDot = dot;
6946 touchingInt = ( minDot*maxDot < 0 );
6951 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6962 u_int1 = u_int2; // to next intersection
6964 } // loop on intersections with one line
6968 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6971 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6974 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6975 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6977 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6980 if ( (f<0) == (l<0) )
6983 if ( hasPositionInfo )
6984 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6986 } // loop on intersections of the tree lines - thorough analysis
6988 if ( !hasPositionInfo )
6990 // gather info on faces position - is face in the outer boundary or not
6991 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6992 findOuterBoundary( u2inters.begin()->second._face );
6995 } // two attempts - with and w/o faces position info in the mesh
6997 return TopAbs_UNKNOWN;
7000 //=======================================================================
7002 * \brief Return elements possibly intersecting the line
7004 //=======================================================================
7006 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7007 SMDSAbs_ElementType type,
7008 vector< const SMDS_MeshElement* >& foundElems)
7010 if ( !_ebbTree || _elementType != type )
7012 if ( _ebbTree ) delete _ebbTree;
7013 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
7015 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7016 _ebbTree->getElementsNearLine( line, suspectFaces );
7017 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7020 //=======================================================================
7022 * \brief Return SMESH_ElementSearcher
7024 //=======================================================================
7026 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7028 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7031 //=======================================================================
7033 * \brief Return true if the point is IN or ON of the element
7035 //=======================================================================
7037 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7039 if ( element->GetType() == SMDSAbs_Volume)
7041 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7044 // get ordered nodes
7046 vector< gp_XYZ > xyz;
7047 vector<const SMDS_MeshNode*> nodeList;
7049 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7050 if ( element->IsQuadratic() ) {
7051 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7052 nodeIt = f->interlacedNodesElemIterator();
7053 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7054 nodeIt = e->interlacedNodesElemIterator();
7056 while ( nodeIt->more() )
7058 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7059 xyz.push_back( TNodeXYZ(node) );
7060 nodeList.push_back(node);
7063 int i, nbNodes = element->NbNodes();
7065 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7067 // compute face normal
7068 gp_Vec faceNorm(0,0,0);
7069 xyz.push_back( xyz.front() );
7070 nodeList.push_back( nodeList.front() );
7071 for ( i = 0; i < nbNodes; ++i )
7073 gp_Vec edge1( xyz[i+1], xyz[i]);
7074 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7075 faceNorm += edge1 ^ edge2;
7077 double normSize = faceNorm.Magnitude();
7078 if ( normSize <= tol )
7080 // degenerated face: point is out if it is out of all face edges
7081 for ( i = 0; i < nbNodes; ++i )
7083 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7084 if ( !isOut( &edge, point, tol ))
7089 faceNorm /= normSize;
7091 // check if the point lays on face plane
7092 gp_Vec n2p( xyz[0], point );
7093 if ( fabs( n2p * faceNorm ) > tol )
7094 return true; // not on face plane
7096 // check if point is out of face boundary:
7097 // define it by closest transition of a ray point->infinity through face boundary
7098 // on the face plane.
7099 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7100 // to find intersections of the ray with the boundary.
7102 gp_Vec plnNorm = ray ^ faceNorm;
7103 normSize = plnNorm.Magnitude();
7104 if ( normSize <= tol ) return false; // point coincides with the first node
7105 plnNorm /= normSize;
7106 // for each node of the face, compute its signed distance to the plane
7107 vector<double> dist( nbNodes + 1);
7108 for ( i = 0; i < nbNodes; ++i )
7110 gp_Vec n2p( xyz[i], point );
7111 dist[i] = n2p * plnNorm;
7113 dist.back() = dist.front();
7114 // find the closest intersection
7116 double rClosest, distClosest = 1e100;;
7118 for ( i = 0; i < nbNodes; ++i )
7121 if ( fabs( dist[i]) < tol )
7123 else if ( fabs( dist[i+1]) < tol )
7125 else if ( dist[i] * dist[i+1] < 0 )
7126 r = dist[i] / ( dist[i] - dist[i+1] );
7128 continue; // no intersection
7129 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7130 gp_Vec p2int ( point, pInt);
7131 if ( p2int * ray > -tol ) // right half-space
7133 double intDist = p2int.SquareMagnitude();
7134 if ( intDist < distClosest )
7139 distClosest = intDist;
7144 return true; // no intesections - out
7146 // analyse transition
7147 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7148 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7149 gp_Vec p2int ( point, pClosest );
7150 bool out = (edgeNorm * p2int) < -tol;
7151 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7154 // ray pass through a face node; analyze transition through an adjacent edge
7155 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7156 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7157 gp_Vec edgeAdjacent( p1, p2 );
7158 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7159 bool out2 = (edgeNorm2 * p2int) < -tol;
7161 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7162 return covexCorner ? (out || out2) : (out && out2);
7164 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7166 // point is out of edge if it is NOT ON any straight part of edge
7167 // (we consider quadratic edge as being composed of two straight parts)
7168 for ( i = 1; i < nbNodes; ++i )
7170 gp_Vec edge( xyz[i-1], xyz[i]);
7171 gp_Vec n1p ( xyz[i-1], point);
7172 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7175 gp_Vec n2p( xyz[i], point );
7176 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7178 return false; // point is ON this part
7182 // Node or 0D element -------------------------------------------------------------------------
7184 gp_Vec n2p ( xyz[0], point );
7185 return n2p.Magnitude() <= tol;
7190 //=======================================================================
7191 //function : SimplifyFace
7193 //=======================================================================
7194 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7195 vector<const SMDS_MeshNode *>& poly_nodes,
7196 vector<int>& quantities) const
7198 int nbNodes = faceNodes.size();
7203 set<const SMDS_MeshNode*> nodeSet;
7205 // get simple seq of nodes
7206 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7207 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7208 int iSimple = 0, nbUnique = 0;
7210 simpleNodes[iSimple++] = faceNodes[0];
7212 for (int iCur = 1; iCur < nbNodes; iCur++) {
7213 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7214 simpleNodes[iSimple++] = faceNodes[iCur];
7215 if (nodeSet.insert( faceNodes[iCur] ).second)
7219 int nbSimple = iSimple;
7220 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7230 bool foundLoop = (nbSimple > nbUnique);
7233 set<const SMDS_MeshNode*> loopSet;
7234 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7235 const SMDS_MeshNode* n = simpleNodes[iSimple];
7236 if (!loopSet.insert( n ).second) {
7240 int iC = 0, curLast = iSimple;
7241 for (; iC < curLast; iC++) {
7242 if (simpleNodes[iC] == n) break;
7244 int loopLen = curLast - iC;
7246 // create sub-element
7248 quantities.push_back(loopLen);
7249 for (; iC < curLast; iC++) {
7250 poly_nodes.push_back(simpleNodes[iC]);
7253 // shift the rest nodes (place from the first loop position)
7254 for (iC = curLast + 1; iC < nbSimple; iC++) {
7255 simpleNodes[iC - loopLen] = simpleNodes[iC];
7257 nbSimple -= loopLen;
7260 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7261 } // while (foundLoop)
7265 quantities.push_back(iSimple);
7266 for (int i = 0; i < iSimple; i++)
7267 poly_nodes.push_back(simpleNodes[i]);
7273 //=======================================================================
7274 //function : MergeNodes
7275 //purpose : In each group, the cdr of nodes are substituted by the first one
7277 //=======================================================================
7279 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7281 MESSAGE("MergeNodes");
7282 myLastCreatedElems.Clear();
7283 myLastCreatedNodes.Clear();
7285 SMESHDS_Mesh* aMesh = GetMeshDS();
7287 TNodeNodeMap nodeNodeMap; // node to replace - new node
7288 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7289 list< int > rmElemIds, rmNodeIds;
7291 // Fill nodeNodeMap and elems
7293 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7294 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7295 list<const SMDS_MeshNode*>& nodes = *grIt;
7296 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7297 const SMDS_MeshNode* nToKeep = *nIt;
7298 //MESSAGE("node to keep " << nToKeep->GetID());
7299 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7300 const SMDS_MeshNode* nToRemove = *nIt;
7301 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7302 if ( nToRemove != nToKeep ) {
7303 //MESSAGE(" node to remove " << nToRemove->GetID());
7304 rmNodeIds.push_back( nToRemove->GetID() );
7305 AddToSameGroups( nToKeep, nToRemove, aMesh );
7308 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7309 while ( invElemIt->more() ) {
7310 const SMDS_MeshElement* elem = invElemIt->next();
7315 // Change element nodes or remove an element
7317 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7318 for ( ; eIt != elems.end(); eIt++ ) {
7319 const SMDS_MeshElement* elem = *eIt;
7320 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7321 int nbNodes = elem->NbNodes();
7322 int aShapeId = FindShape( elem );
7324 set<const SMDS_MeshNode*> nodeSet;
7325 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7326 int iUnique = 0, iCur = 0, nbRepl = 0;
7327 vector<int> iRepl( nbNodes );
7329 // get new seq of nodes
7330 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7331 while ( itN->more() ) {
7332 const SMDS_MeshNode* n =
7333 static_cast<const SMDS_MeshNode*>( itN->next() );
7335 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7336 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7338 // BUG 0020185: begin
7340 bool stopRecur = false;
7341 set<const SMDS_MeshNode*> nodesRecur;
7342 nodesRecur.insert(n);
7343 while (!stopRecur) {
7344 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7345 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7346 n = (*nnIt_i).second;
7347 if (!nodesRecur.insert(n).second) {
7348 // error: recursive dependancy
7357 iRepl[ nbRepl++ ] = iCur;
7359 curNodes[ iCur ] = n;
7360 bool isUnique = nodeSet.insert( n ).second;
7362 uniqueNodes[ iUnique++ ] = n;
7366 // Analyse element topology after replacement
7369 int nbUniqueNodes = nodeSet.size();
7370 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7371 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7372 // Polygons and Polyhedral volumes
7373 if (elem->IsPoly()) {
7375 if (elem->GetType() == SMDSAbs_Face) {
7377 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7379 for (; inode < nbNodes; inode++) {
7380 face_nodes[inode] = curNodes[inode];
7383 vector<const SMDS_MeshNode *> polygons_nodes;
7384 vector<int> quantities;
7385 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7388 for (int iface = 0; iface < nbNew; iface++) {
7389 int nbNodes = quantities[iface];
7390 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7391 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7392 poly_nodes[ii] = polygons_nodes[inode];
7394 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7395 myLastCreatedElems.Append(newElem);
7397 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7400 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7401 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7402 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7404 if (nbNew > 0) quid = nbNew - 1;
7405 vector<int> newquant(quantities.begin()+quid, quantities.end());
7406 const SMDS_MeshElement* newElem = 0;
7407 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7408 myLastCreatedElems.Append(newElem);
7409 if ( aShapeId && newElem )
7410 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7411 rmElemIds.push_back(elem->GetID());
7414 rmElemIds.push_back(elem->GetID());
7418 else if (elem->GetType() == SMDSAbs_Volume) {
7419 // Polyhedral volume
7420 if (nbUniqueNodes < 4) {
7421 rmElemIds.push_back(elem->GetID());
7424 // each face has to be analyzed in order to check volume validity
7425 const SMDS_VtkVolume* aPolyedre =
7426 dynamic_cast<const SMDS_VtkVolume*>( elem );
7428 int nbFaces = aPolyedre->NbFaces();
7430 vector<const SMDS_MeshNode *> poly_nodes;
7431 vector<int> quantities;
7433 for (int iface = 1; iface <= nbFaces; iface++) {
7434 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7435 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7437 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7438 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7439 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7440 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7441 faceNode = (*nnIt).second;
7443 faceNodes[inode - 1] = faceNode;
7446 SimplifyFace(faceNodes, poly_nodes, quantities);
7449 if (quantities.size() > 3) {
7450 // to be done: remove coincident faces
7453 if (quantities.size() > 3)
7455 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7456 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7457 const SMDS_MeshElement* newElem = 0;
7458 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7459 myLastCreatedElems.Append(newElem);
7460 if ( aShapeId && newElem )
7461 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7462 rmElemIds.push_back(elem->GetID());
7466 rmElemIds.push_back(elem->GetID());
7477 // TODO not all the possible cases are solved. Find something more generic?
7478 switch ( nbNodes ) {
7479 case 2: ///////////////////////////////////// EDGE
7480 isOk = false; break;
7481 case 3: ///////////////////////////////////// TRIANGLE
7482 isOk = false; break;
7484 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7486 else { //////////////////////////////////// QUADRANGLE
7487 if ( nbUniqueNodes < 3 )
7489 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7490 isOk = false; // opposite nodes stick
7491 //MESSAGE("isOk " << isOk);
7494 case 6: ///////////////////////////////////// PENTAHEDRON
7495 if ( nbUniqueNodes == 4 ) {
7496 // ---------------------------------> tetrahedron
7498 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7499 // all top nodes stick: reverse a bottom
7500 uniqueNodes[ 0 ] = curNodes [ 1 ];
7501 uniqueNodes[ 1 ] = curNodes [ 0 ];
7503 else if (nbRepl == 3 &&
7504 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7505 // all bottom nodes stick: set a top before
7506 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7507 uniqueNodes[ 0 ] = curNodes [ 3 ];
7508 uniqueNodes[ 1 ] = curNodes [ 4 ];
7509 uniqueNodes[ 2 ] = curNodes [ 5 ];
7511 else if (nbRepl == 4 &&
7512 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7513 // a lateral face turns into a line: reverse a bottom
7514 uniqueNodes[ 0 ] = curNodes [ 1 ];
7515 uniqueNodes[ 1 ] = curNodes [ 0 ];
7520 else if ( nbUniqueNodes == 5 ) {
7521 // PENTAHEDRON --------------------> 2 tetrahedrons
7522 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7523 // a bottom node sticks with a linked top one
7525 SMDS_MeshElement* newElem =
7526 aMesh->AddVolume(curNodes[ 3 ],
7529 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7530 myLastCreatedElems.Append(newElem);
7532 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7533 // 2. : reverse a bottom
7534 uniqueNodes[ 0 ] = curNodes [ 1 ];
7535 uniqueNodes[ 1 ] = curNodes [ 0 ];
7545 if(elem->IsQuadratic()) { // Quadratic quadrangle
7557 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7560 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7562 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7563 uniqueNodes[0] = curNodes[0];
7564 uniqueNodes[1] = curNodes[2];
7565 uniqueNodes[2] = curNodes[3];
7566 uniqueNodes[3] = curNodes[5];
7567 uniqueNodes[4] = curNodes[6];
7568 uniqueNodes[5] = curNodes[7];
7571 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7572 uniqueNodes[0] = curNodes[0];
7573 uniqueNodes[1] = curNodes[1];
7574 uniqueNodes[2] = curNodes[2];
7575 uniqueNodes[3] = curNodes[4];
7576 uniqueNodes[4] = curNodes[5];
7577 uniqueNodes[5] = curNodes[6];
7580 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7581 uniqueNodes[0] = curNodes[1];
7582 uniqueNodes[1] = curNodes[2];
7583 uniqueNodes[2] = curNodes[3];
7584 uniqueNodes[3] = curNodes[5];
7585 uniqueNodes[4] = curNodes[6];
7586 uniqueNodes[5] = curNodes[0];
7589 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7590 uniqueNodes[0] = curNodes[0];
7591 uniqueNodes[1] = curNodes[1];
7592 uniqueNodes[2] = curNodes[3];
7593 uniqueNodes[3] = curNodes[4];
7594 uniqueNodes[4] = curNodes[6];
7595 uniqueNodes[5] = curNodes[7];
7598 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7599 uniqueNodes[0] = curNodes[0];
7600 uniqueNodes[1] = curNodes[2];
7601 uniqueNodes[2] = curNodes[3];
7602 uniqueNodes[3] = curNodes[1];
7603 uniqueNodes[4] = curNodes[6];
7604 uniqueNodes[5] = curNodes[7];
7607 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7608 uniqueNodes[0] = curNodes[0];
7609 uniqueNodes[1] = curNodes[1];
7610 uniqueNodes[2] = curNodes[2];
7611 uniqueNodes[3] = curNodes[4];
7612 uniqueNodes[4] = curNodes[5];
7613 uniqueNodes[5] = curNodes[7];
7616 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7617 uniqueNodes[0] = curNodes[0];
7618 uniqueNodes[1] = curNodes[1];
7619 uniqueNodes[2] = curNodes[3];
7620 uniqueNodes[3] = curNodes[4];
7621 uniqueNodes[4] = curNodes[2];
7622 uniqueNodes[5] = curNodes[7];
7625 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7626 uniqueNodes[0] = curNodes[0];
7627 uniqueNodes[1] = curNodes[1];
7628 uniqueNodes[2] = curNodes[2];
7629 uniqueNodes[3] = curNodes[4];
7630 uniqueNodes[4] = curNodes[5];
7631 uniqueNodes[5] = curNodes[3];
7636 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7639 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7643 //////////////////////////////////// HEXAHEDRON
7645 SMDS_VolumeTool hexa (elem);
7646 hexa.SetExternalNormal();
7647 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7648 //////////////////////// ---> tetrahedron
7649 for ( int iFace = 0; iFace < 6; iFace++ ) {
7650 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7651 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7652 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7653 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7654 // one face turns into a point ...
7655 int iOppFace = hexa.GetOppFaceIndex( iFace );
7656 ind = hexa.GetFaceNodesIndices( iOppFace );
7658 iUnique = 2; // reverse a tetrahedron bottom
7659 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7660 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7662 else if ( iUnique >= 0 )
7663 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7665 if ( nbStick == 1 ) {
7666 // ... and the opposite one - into a triangle.
7668 ind = hexa.GetFaceNodesIndices( iFace );
7669 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7676 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7677 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7678 for ( int iFace = 0; iFace < 6; iFace++ ) {
7679 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7680 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7681 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7682 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7683 // one face turns into a point ...
7684 int iOppFace = hexa.GetOppFaceIndex( iFace );
7685 ind = hexa.GetFaceNodesIndices( iOppFace );
7687 iUnique = 2; // reverse a tetrahedron 1 bottom
7688 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7689 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7691 else if ( iUnique >= 0 )
7692 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7694 if ( nbStick == 0 ) {
7695 // ... and the opposite one is a quadrangle
7697 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7698 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7701 SMDS_MeshElement* newElem =
7702 aMesh->AddVolume(curNodes[ind[ 0 ]],
7705 curNodes[indTop[ 0 ]]);
7706 myLastCreatedElems.Append(newElem);
7708 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7715 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7716 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7717 // find indices of quad and tri faces
7718 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7719 for ( iFace = 0; iFace < 6; iFace++ ) {
7720 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7722 for ( iCur = 0; iCur < 4; iCur++ )
7723 nodeSet.insert( curNodes[ind[ iCur ]] );
7724 nbUniqueNodes = nodeSet.size();
7725 if ( nbUniqueNodes == 3 )
7726 iTriFace[ nbTri++ ] = iFace;
7727 else if ( nbUniqueNodes == 4 )
7728 iQuadFace[ nbQuad++ ] = iFace;
7730 if (nbQuad == 2 && nbTri == 4 &&
7731 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7732 // 2 opposite quadrangles stuck with a diagonal;
7733 // sample groups of merged indices: (0-4)(2-6)
7734 // --------------------------------------------> 2 tetrahedrons
7735 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7736 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7737 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7738 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7739 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7740 // stuck with 0-2 diagonal
7748 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7749 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7750 // stuck with 1-3 diagonal
7762 uniqueNodes[ 0 ] = curNodes [ i0 ];
7763 uniqueNodes[ 1 ] = curNodes [ i1d ];
7764 uniqueNodes[ 2 ] = curNodes [ i3d ];
7765 uniqueNodes[ 3 ] = curNodes [ i0t ];
7768 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7772 myLastCreatedElems.Append(newElem);
7774 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7777 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7778 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7779 // --------------------------------------------> prism
7780 // find 2 opposite triangles
7782 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7783 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7784 // find indices of kept and replaced nodes
7785 // and fill unique nodes of 2 opposite triangles
7786 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7787 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7788 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7789 // fill unique nodes
7792 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7793 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7794 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7796 // iCur of a linked node of the opposite face (make normals co-directed):
7797 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7798 // check that correspondent corners of triangles are linked
7799 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7802 uniqueNodes[ iUnique ] = n;
7803 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7812 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7818 } // switch ( nbNodes )
7820 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7823 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7824 // Change nodes of polyedre
7825 const SMDS_VtkVolume* aPolyedre =
7826 dynamic_cast<const SMDS_VtkVolume*>( elem );
7828 int nbFaces = aPolyedre->NbFaces();
7830 vector<const SMDS_MeshNode *> poly_nodes;
7831 vector<int> quantities (nbFaces);
7833 for (int iface = 1; iface <= nbFaces; iface++) {
7834 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7835 quantities[iface - 1] = nbFaceNodes;
7837 for (inode = 1; inode <= nbFaceNodes; inode++) {
7838 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7840 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7841 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7842 curNode = (*nnIt).second;
7844 poly_nodes.push_back(curNode);
7847 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7851 //int elemId = elem->GetID();
7852 //MESSAGE("Change regular element or polygon " << elemId);
7853 SMDSAbs_ElementType etyp = elem->GetType();
7854 uniqueNodes.resize(nbUniqueNodes);
7855 SMDS_MeshElement* newElem = 0;
7856 if (elem->GetEntityType() == SMDSEntity_Polygon)
7857 newElem = this->AddElement(uniqueNodes, etyp, true);
7859 newElem = this->AddElement(uniqueNodes, etyp, false);
7862 myLastCreatedElems.Append(newElem);
7864 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7866 aMesh->RemoveElement(elem);
7870 // Remove invalid regular element or invalid polygon
7871 //MESSAGE("Remove invalid " << elem->GetID());
7872 rmElemIds.push_back( elem->GetID() );
7875 } // loop on elements
7877 // Remove bad elements, then equal nodes (order important)
7879 Remove( rmElemIds, false );
7880 Remove( rmNodeIds, true );
7885 // ========================================================
7886 // class : SortableElement
7887 // purpose : allow sorting elements basing on their nodes
7888 // ========================================================
7889 class SortableElement : public set <const SMDS_MeshElement*>
7893 SortableElement( const SMDS_MeshElement* theElem )
7896 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7897 while ( nodeIt->more() )
7898 this->insert( nodeIt->next() );
7901 const SMDS_MeshElement* Get() const
7904 void Set(const SMDS_MeshElement* e) const
7909 mutable const SMDS_MeshElement* myElem;
7912 //=======================================================================
7913 //function : FindEqualElements
7914 //purpose : Return list of group of elements built on the same nodes.
7915 // Search among theElements or in the whole mesh if theElements is empty
7916 //=======================================================================
7917 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7918 TListOfListOfElementsID & theGroupsOfElementsID)
7920 myLastCreatedElems.Clear();
7921 myLastCreatedNodes.Clear();
7923 typedef set<const SMDS_MeshElement*> TElemsSet;
7924 typedef map< SortableElement, int > TMapOfNodeSet;
7925 typedef list<int> TGroupOfElems;
7928 if ( theElements.empty() )
7929 { // get all elements in the mesh
7930 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7931 while ( eIt->more() )
7932 elems.insert( elems.end(), eIt->next());
7935 elems = theElements;
7937 vector< TGroupOfElems > arrayOfGroups;
7938 TGroupOfElems groupOfElems;
7939 TMapOfNodeSet mapOfNodeSet;
7941 TElemsSet::iterator elemIt = elems.begin();
7942 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7943 const SMDS_MeshElement* curElem = *elemIt;
7944 SortableElement SE(curElem);
7947 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7948 if( !(pp.second) ) {
7949 TMapOfNodeSet::iterator& itSE = pp.first;
7950 ind = (*itSE).second;
7951 arrayOfGroups[ind].push_back(curElem->GetID());
7954 groupOfElems.clear();
7955 groupOfElems.push_back(curElem->GetID());
7956 arrayOfGroups.push_back(groupOfElems);
7961 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7962 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7963 groupOfElems = *groupIt;
7964 if ( groupOfElems.size() > 1 ) {
7965 groupOfElems.sort();
7966 theGroupsOfElementsID.push_back(groupOfElems);
7971 //=======================================================================
7972 //function : MergeElements
7973 //purpose : In each given group, substitute all elements by the first one.
7974 //=======================================================================
7976 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7978 myLastCreatedElems.Clear();
7979 myLastCreatedNodes.Clear();
7981 typedef list<int> TListOfIDs;
7982 TListOfIDs rmElemIds; // IDs of elems to remove
7984 SMESHDS_Mesh* aMesh = GetMeshDS();
7986 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7987 while ( groupsIt != theGroupsOfElementsID.end() ) {
7988 TListOfIDs& aGroupOfElemID = *groupsIt;
7989 aGroupOfElemID.sort();
7990 int elemIDToKeep = aGroupOfElemID.front();
7991 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7992 aGroupOfElemID.pop_front();
7993 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7994 while ( idIt != aGroupOfElemID.end() ) {
7995 int elemIDToRemove = *idIt;
7996 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7997 // add the kept element in groups of removed one (PAL15188)
7998 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7999 rmElemIds.push_back( elemIDToRemove );
8005 Remove( rmElemIds, false );
8008 //=======================================================================
8009 //function : MergeEqualElements
8010 //purpose : Remove all but one of elements built on the same nodes.
8011 //=======================================================================
8013 void SMESH_MeshEditor::MergeEqualElements()
8015 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8016 to merge equal elements in the whole mesh */
8017 TListOfListOfElementsID aGroupsOfElementsID;
8018 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8019 MergeElements(aGroupsOfElementsID);
8022 //=======================================================================
8023 //function : FindFaceInSet
8024 //purpose : Return a face having linked nodes n1 and n2 and which is
8025 // - not in avoidSet,
8026 // - in elemSet provided that !elemSet.empty()
8027 // i1 and i2 optionally returns indices of n1 and n2
8028 //=======================================================================
8030 const SMDS_MeshElement*
8031 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8032 const SMDS_MeshNode* n2,
8033 const TIDSortedElemSet& elemSet,
8034 const TIDSortedElemSet& avoidSet,
8040 const SMDS_MeshElement* face = 0;
8042 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8043 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8044 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8046 //MESSAGE("in while ( invElemIt->more() && !face )");
8047 const SMDS_MeshElement* elem = invElemIt->next();
8048 if (avoidSet.count( elem ))
8050 if ( !elemSet.empty() && !elemSet.count( elem ))
8053 i1 = elem->GetNodeIndex( n1 );
8054 // find a n2 linked to n1
8055 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8056 for ( int di = -1; di < 2 && !face; di += 2 )
8058 i2 = (i1+di+nbN) % nbN;
8059 if ( elem->GetNode( i2 ) == n2 )
8062 if ( !face && elem->IsQuadratic())
8064 // analysis for quadratic elements using all nodes
8065 const SMDS_VtkFace* F =
8066 dynamic_cast<const SMDS_VtkFace*>(elem);
8067 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8068 // use special nodes iterator
8069 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8070 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8071 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8073 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8074 if ( n1 == prevN && n2 == n )
8078 else if ( n2 == prevN && n1 == n )
8080 face = elem; swap( i1, i2 );
8086 if ( n1ind ) *n1ind = i1;
8087 if ( n2ind ) *n2ind = i2;
8091 //=======================================================================
8092 //function : findAdjacentFace
8094 //=======================================================================
8096 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8097 const SMDS_MeshNode* n2,
8098 const SMDS_MeshElement* elem)
8100 TIDSortedElemSet elemSet, avoidSet;
8102 avoidSet.insert ( elem );
8103 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8106 //=======================================================================
8107 //function : FindFreeBorder
8109 //=======================================================================
8111 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8113 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8114 const SMDS_MeshNode* theSecondNode,
8115 const SMDS_MeshNode* theLastNode,
8116 list< const SMDS_MeshNode* > & theNodes,
8117 list< const SMDS_MeshElement* >& theFaces)
8119 if ( !theFirstNode || !theSecondNode )
8121 // find border face between theFirstNode and theSecondNode
8122 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8126 theFaces.push_back( curElem );
8127 theNodes.push_back( theFirstNode );
8128 theNodes.push_back( theSecondNode );
8130 //vector<const SMDS_MeshNode*> nodes;
8131 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8132 TIDSortedElemSet foundElems;
8133 bool needTheLast = ( theLastNode != 0 );
8135 while ( nStart != theLastNode ) {
8136 if ( nStart == theFirstNode )
8137 return !needTheLast;
8139 // find all free border faces sharing form nStart
8141 list< const SMDS_MeshElement* > curElemList;
8142 list< const SMDS_MeshNode* > nStartList;
8143 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8144 while ( invElemIt->more() ) {
8145 const SMDS_MeshElement* e = invElemIt->next();
8146 if ( e == curElem || foundElems.insert( e ).second ) {
8148 int iNode = 0, nbNodes = e->NbNodes();
8149 //const SMDS_MeshNode* nodes[nbNodes+1];
8150 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8152 if(e->IsQuadratic()) {
8153 const SMDS_VtkFace* F =
8154 dynamic_cast<const SMDS_VtkFace*>(e);
8155 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8156 // use special nodes iterator
8157 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8158 while( anIter->more() ) {
8159 nodes[ iNode++ ] = cast2Node(anIter->next());
8163 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8164 while ( nIt->more() )
8165 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8167 nodes[ iNode ] = nodes[ 0 ];
8169 for ( iNode = 0; iNode < nbNodes; iNode++ )
8170 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8171 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8172 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8174 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8175 curElemList.push_back( e );
8179 // analyse the found
8181 int nbNewBorders = curElemList.size();
8182 if ( nbNewBorders == 0 ) {
8183 // no free border furthermore
8184 return !needTheLast;
8186 else if ( nbNewBorders == 1 ) {
8187 // one more element found
8189 nStart = nStartList.front();
8190 curElem = curElemList.front();
8191 theFaces.push_back( curElem );
8192 theNodes.push_back( nStart );
8195 // several continuations found
8196 list< const SMDS_MeshElement* >::iterator curElemIt;
8197 list< const SMDS_MeshNode* >::iterator nStartIt;
8198 // check if one of them reached the last node
8199 if ( needTheLast ) {
8200 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8201 curElemIt!= curElemList.end();
8202 curElemIt++, nStartIt++ )
8203 if ( *nStartIt == theLastNode ) {
8204 theFaces.push_back( *curElemIt );
8205 theNodes.push_back( *nStartIt );
8209 // find the best free border by the continuations
8210 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8211 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8212 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8213 curElemIt!= curElemList.end();
8214 curElemIt++, nStartIt++ )
8216 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8217 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8218 // find one more free border
8219 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8223 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8224 // choice: clear a worse one
8225 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8226 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8227 contNodes[ iWorse ].clear();
8228 contFaces[ iWorse ].clear();
8231 if ( contNodes[0].empty() && contNodes[1].empty() )
8234 // append the best free border
8235 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8236 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8237 theNodes.pop_back(); // remove nIgnore
8238 theNodes.pop_back(); // remove nStart
8239 theFaces.pop_back(); // remove curElem
8240 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8241 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8242 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8243 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8246 } // several continuations found
8247 } // while ( nStart != theLastNode )
8252 //=======================================================================
8253 //function : CheckFreeBorderNodes
8254 //purpose : Return true if the tree nodes are on a free border
8255 //=======================================================================
8257 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8258 const SMDS_MeshNode* theNode2,
8259 const SMDS_MeshNode* theNode3)
8261 list< const SMDS_MeshNode* > nodes;
8262 list< const SMDS_MeshElement* > faces;
8263 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8266 //=======================================================================
8267 //function : SewFreeBorder
8269 //=======================================================================
8271 SMESH_MeshEditor::Sew_Error
8272 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8273 const SMDS_MeshNode* theBordSecondNode,
8274 const SMDS_MeshNode* theBordLastNode,
8275 const SMDS_MeshNode* theSideFirstNode,
8276 const SMDS_MeshNode* theSideSecondNode,
8277 const SMDS_MeshNode* theSideThirdNode,
8278 const bool theSideIsFreeBorder,
8279 const bool toCreatePolygons,
8280 const bool toCreatePolyedrs)
8282 myLastCreatedElems.Clear();
8283 myLastCreatedNodes.Clear();
8285 MESSAGE("::SewFreeBorder()");
8286 Sew_Error aResult = SEW_OK;
8288 // ====================================
8289 // find side nodes and elements
8290 // ====================================
8292 list< const SMDS_MeshNode* > nSide[ 2 ];
8293 list< const SMDS_MeshElement* > eSide[ 2 ];
8294 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8295 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8299 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8300 nSide[0], eSide[0])) {
8301 MESSAGE(" Free Border 1 not found " );
8302 aResult = SEW_BORDER1_NOT_FOUND;
8304 if (theSideIsFreeBorder) {
8307 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8308 nSide[1], eSide[1])) {
8309 MESSAGE(" Free Border 2 not found " );
8310 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8313 if ( aResult != SEW_OK )
8316 if (!theSideIsFreeBorder) {
8320 // -------------------------------------------------------------------------
8322 // 1. If nodes to merge are not coincident, move nodes of the free border
8323 // from the coord sys defined by the direction from the first to last
8324 // nodes of the border to the correspondent sys of the side 2
8325 // 2. On the side 2, find the links most co-directed with the correspondent
8326 // links of the free border
8327 // -------------------------------------------------------------------------
8329 // 1. Since sewing may break if there are volumes to split on the side 2,
8330 // we wont move nodes but just compute new coordinates for them
8331 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8332 TNodeXYZMap nBordXYZ;
8333 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8334 list< const SMDS_MeshNode* >::iterator nBordIt;
8336 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8337 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8338 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8339 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8340 double tol2 = 1.e-8;
8341 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8342 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8343 // Need node movement.
8345 // find X and Z axes to create trsf
8346 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8348 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8350 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8353 gp_Ax3 toBordAx( Pb1, Zb, X );
8354 gp_Ax3 fromSideAx( Ps1, Zs, X );
8355 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8357 gp_Trsf toBordSys, fromSide2Sys;
8358 toBordSys.SetTransformation( toBordAx );
8359 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8360 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8363 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8364 const SMDS_MeshNode* n = *nBordIt;
8365 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8366 toBordSys.Transforms( xyz );
8367 fromSide2Sys.Transforms( xyz );
8368 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8372 // just insert nodes XYZ in the nBordXYZ map
8373 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8374 const SMDS_MeshNode* n = *nBordIt;
8375 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8379 // 2. On the side 2, find the links most co-directed with the correspondent
8380 // links of the free border
8382 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8383 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8384 sideNodes.push_back( theSideFirstNode );
8386 bool hasVolumes = false;
8387 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8388 set<long> foundSideLinkIDs, checkedLinkIDs;
8389 SMDS_VolumeTool volume;
8390 //const SMDS_MeshNode* faceNodes[ 4 ];
8392 const SMDS_MeshNode* sideNode;
8393 const SMDS_MeshElement* sideElem;
8394 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8395 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8396 nBordIt = bordNodes.begin();
8398 // border node position and border link direction to compare with
8399 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8400 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8401 // choose next side node by link direction or by closeness to
8402 // the current border node:
8403 bool searchByDir = ( *nBordIt != theBordLastNode );
8405 // find the next node on the Side 2
8407 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8409 checkedLinkIDs.clear();
8410 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8412 // loop on inverse elements of current node (prevSideNode) on the Side 2
8413 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8414 while ( invElemIt->more() )
8416 const SMDS_MeshElement* elem = invElemIt->next();
8417 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8418 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8419 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8420 bool isVolume = volume.Set( elem );
8421 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8422 if ( isVolume ) // --volume
8424 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8425 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8426 if(elem->IsQuadratic()) {
8427 const SMDS_VtkFace* F =
8428 dynamic_cast<const SMDS_VtkFace*>(elem);
8429 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8430 // use special nodes iterator
8431 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8432 while( anIter->more() ) {
8433 nodes[ iNode ] = cast2Node(anIter->next());
8434 if ( nodes[ iNode++ ] == prevSideNode )
8435 iPrevNode = iNode - 1;
8439 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8440 while ( nIt->more() ) {
8441 nodes[ iNode ] = cast2Node( nIt->next() );
8442 if ( nodes[ iNode++ ] == prevSideNode )
8443 iPrevNode = iNode - 1;
8446 // there are 2 links to check
8451 // loop on links, to be precise, on the second node of links
8452 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8453 const SMDS_MeshNode* n = nodes[ iNode ];
8455 if ( !volume.IsLinked( n, prevSideNode ))
8459 if ( iNode ) // a node before prevSideNode
8460 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8461 else // a node after prevSideNode
8462 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8464 // check if this link was already used
8465 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8466 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8467 if (!isJustChecked &&
8468 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8470 // test a link geometrically
8471 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8472 bool linkIsBetter = false;
8473 double dot = 0.0, dist = 0.0;
8474 if ( searchByDir ) { // choose most co-directed link
8475 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8476 linkIsBetter = ( dot > maxDot );
8478 else { // choose link with the node closest to bordPos
8479 dist = ( nextXYZ - bordPos ).SquareModulus();
8480 linkIsBetter = ( dist < minDist );
8482 if ( linkIsBetter ) {
8491 } // loop on inverse elements of prevSideNode
8494 MESSAGE(" Cant find path by links of the Side 2 ");
8495 return SEW_BAD_SIDE_NODES;
8497 sideNodes.push_back( sideNode );
8498 sideElems.push_back( sideElem );
8499 foundSideLinkIDs.insert ( linkID );
8500 prevSideNode = sideNode;
8502 if ( *nBordIt == theBordLastNode )
8503 searchByDir = false;
8505 // find the next border link to compare with
8506 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8507 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8508 // move to next border node if sideNode is before forward border node (bordPos)
8509 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8510 prevBordNode = *nBordIt;
8512 bordPos = nBordXYZ[ *nBordIt ];
8513 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8514 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8518 while ( sideNode != theSideSecondNode );
8520 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8521 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8522 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8524 } // end nodes search on the side 2
8526 // ============================
8527 // sew the border to the side 2
8528 // ============================
8530 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8531 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8533 TListOfListOfNodes nodeGroupsToMerge;
8534 if ( nbNodes[0] == nbNodes[1] ||
8535 ( theSideIsFreeBorder && !theSideThirdNode)) {
8537 // all nodes are to be merged
8539 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8540 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8541 nIt[0]++, nIt[1]++ )
8543 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8544 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8545 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8550 // insert new nodes into the border and the side to get equal nb of segments
8552 // get normalized parameters of nodes on the borders
8553 //double param[ 2 ][ maxNbNodes ];
8555 param[0] = new double [ maxNbNodes ];
8556 param[1] = new double [ maxNbNodes ];
8558 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8559 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8560 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8561 const SMDS_MeshNode* nPrev = *nIt;
8562 double bordLength = 0;
8563 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8564 const SMDS_MeshNode* nCur = *nIt;
8565 gp_XYZ segment (nCur->X() - nPrev->X(),
8566 nCur->Y() - nPrev->Y(),
8567 nCur->Z() - nPrev->Z());
8568 double segmentLen = segment.Modulus();
8569 bordLength += segmentLen;
8570 param[ iBord ][ iNode ] = bordLength;
8573 // normalize within [0,1]
8574 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8575 param[ iBord ][ iNode ] /= bordLength;
8579 // loop on border segments
8580 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8581 int i[ 2 ] = { 0, 0 };
8582 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8583 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8585 TElemOfNodeListMap insertMap;
8586 TElemOfNodeListMap::iterator insertMapIt;
8588 // key: elem to insert nodes into
8589 // value: 2 nodes to insert between + nodes to be inserted
8591 bool next[ 2 ] = { false, false };
8593 // find min adjacent segment length after sewing
8594 double nextParam = 10., prevParam = 0;
8595 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8596 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8597 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8598 if ( i[ iBord ] > 0 )
8599 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8601 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8602 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8603 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8605 // choose to insert or to merge nodes
8606 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8607 if ( Abs( du ) <= minSegLen * 0.2 ) {
8610 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8611 const SMDS_MeshNode* n0 = *nIt[0];
8612 const SMDS_MeshNode* n1 = *nIt[1];
8613 nodeGroupsToMerge.back().push_back( n1 );
8614 nodeGroupsToMerge.back().push_back( n0 );
8615 // position of node of the border changes due to merge
8616 param[ 0 ][ i[0] ] += du;
8617 // move n1 for the sake of elem shape evaluation during insertion.
8618 // n1 will be removed by MergeNodes() anyway
8619 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8620 next[0] = next[1] = true;
8625 int intoBord = ( du < 0 ) ? 0 : 1;
8626 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8627 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8628 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8629 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8630 if ( intoBord == 1 ) {
8631 // move node of the border to be on a link of elem of the side
8632 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8633 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8634 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8635 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8636 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8638 insertMapIt = insertMap.find( elem );
8639 bool notFound = ( insertMapIt == insertMap.end() );
8640 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8642 // insert into another link of the same element:
8643 // 1. perform insertion into the other link of the elem
8644 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8645 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8646 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8647 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8648 // 2. perform insertion into the link of adjacent faces
8650 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8652 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8656 if (toCreatePolyedrs) {
8657 // perform insertion into the links of adjacent volumes
8658 UpdateVolumes(n12, n22, nodeList);
8660 // 3. find an element appeared on n1 and n2 after the insertion
8661 insertMap.erase( elem );
8662 elem = findAdjacentFace( n1, n2, 0 );
8664 if ( notFound || otherLink ) {
8665 // add element and nodes of the side into the insertMap
8666 insertMapIt = insertMap.insert
8667 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8668 (*insertMapIt).second.push_back( n1 );
8669 (*insertMapIt).second.push_back( n2 );
8671 // add node to be inserted into elem
8672 (*insertMapIt).second.push_back( nIns );
8673 next[ 1 - intoBord ] = true;
8676 // go to the next segment
8677 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8678 if ( next[ iBord ] ) {
8679 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8681 nPrev[ iBord ] = *nIt[ iBord ];
8682 nIt[ iBord ]++; i[ iBord ]++;
8686 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8688 // perform insertion of nodes into elements
8690 for (insertMapIt = insertMap.begin();
8691 insertMapIt != insertMap.end();
8694 const SMDS_MeshElement* elem = (*insertMapIt).first;
8695 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8696 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8697 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8699 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8701 if ( !theSideIsFreeBorder ) {
8702 // look for and insert nodes into the faces adjacent to elem
8704 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8706 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8711 if (toCreatePolyedrs) {
8712 // perform insertion into the links of adjacent volumes
8713 UpdateVolumes(n1, n2, nodeList);
8719 } // end: insert new nodes
8721 MergeNodes ( nodeGroupsToMerge );
8726 //=======================================================================
8727 //function : InsertNodesIntoLink
8728 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8729 // and theBetweenNode2 and split theElement
8730 //=======================================================================
8732 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8733 const SMDS_MeshNode* theBetweenNode1,
8734 const SMDS_MeshNode* theBetweenNode2,
8735 list<const SMDS_MeshNode*>& theNodesToInsert,
8736 const bool toCreatePoly)
8738 if ( theFace->GetType() != SMDSAbs_Face ) return;
8740 // find indices of 2 link nodes and of the rest nodes
8741 int iNode = 0, il1, il2, i3, i4;
8742 il1 = il2 = i3 = i4 = -1;
8743 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8744 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8746 if(theFace->IsQuadratic()) {
8747 const SMDS_VtkFace* F =
8748 dynamic_cast<const SMDS_VtkFace*>(theFace);
8749 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8750 // use special nodes iterator
8751 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8752 while( anIter->more() ) {
8753 const SMDS_MeshNode* n = cast2Node(anIter->next());
8754 if ( n == theBetweenNode1 )
8756 else if ( n == theBetweenNode2 )
8762 nodes[ iNode++ ] = n;
8766 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8767 while ( nodeIt->more() ) {
8768 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8769 if ( n == theBetweenNode1 )
8771 else if ( n == theBetweenNode2 )
8777 nodes[ iNode++ ] = n;
8780 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8783 // arrange link nodes to go one after another regarding the face orientation
8784 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8785 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8790 aNodesToInsert.reverse();
8792 // check that not link nodes of a quadrangles are in good order
8793 int nbFaceNodes = theFace->NbNodes();
8794 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8800 if (toCreatePoly || theFace->IsPoly()) {
8803 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8805 // add nodes of face up to first node of link
8808 if(theFace->IsQuadratic()) {
8809 const SMDS_VtkFace* F =
8810 dynamic_cast<const SMDS_VtkFace*>(theFace);
8811 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8812 // use special nodes iterator
8813 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8814 while( anIter->more() && !isFLN ) {
8815 const SMDS_MeshNode* n = cast2Node(anIter->next());
8816 poly_nodes[iNode++] = n;
8817 if (n == nodes[il1]) {
8821 // add nodes to insert
8822 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8823 for (; nIt != aNodesToInsert.end(); nIt++) {
8824 poly_nodes[iNode++] = *nIt;
8826 // add nodes of face starting from last node of link
8827 while ( anIter->more() ) {
8828 poly_nodes[iNode++] = cast2Node(anIter->next());
8832 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8833 while ( nodeIt->more() && !isFLN ) {
8834 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8835 poly_nodes[iNode++] = n;
8836 if (n == nodes[il1]) {
8840 // add nodes to insert
8841 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8842 for (; nIt != aNodesToInsert.end(); nIt++) {
8843 poly_nodes[iNode++] = *nIt;
8845 // add nodes of face starting from last node of link
8846 while ( nodeIt->more() ) {
8847 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8848 poly_nodes[iNode++] = n;
8852 // edit or replace the face
8853 SMESHDS_Mesh *aMesh = GetMeshDS();
8855 if (theFace->IsPoly()) {
8856 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8859 int aShapeId = FindShape( theFace );
8861 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8862 myLastCreatedElems.Append(newElem);
8863 if ( aShapeId && newElem )
8864 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8866 aMesh->RemoveElement(theFace);
8871 SMESHDS_Mesh *aMesh = GetMeshDS();
8872 if( !theFace->IsQuadratic() ) {
8874 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8875 int nbLinkNodes = 2 + aNodesToInsert.size();
8876 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8877 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8878 linkNodes[ 0 ] = nodes[ il1 ];
8879 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8880 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8881 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8882 linkNodes[ iNode++ ] = *nIt;
8884 // decide how to split a quadrangle: compare possible variants
8885 // and choose which of splits to be a quadrangle
8886 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8887 if ( nbFaceNodes == 3 ) {
8888 iBestQuad = nbSplits;
8891 else if ( nbFaceNodes == 4 ) {
8892 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8893 double aBestRate = DBL_MAX;
8894 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8896 double aBadRate = 0;
8897 // evaluate elements quality
8898 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8899 if ( iSplit == iQuad ) {
8900 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8904 aBadRate += getBadRate( &quad, aCrit );
8907 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8909 nodes[ iSplit < iQuad ? i4 : i3 ]);
8910 aBadRate += getBadRate( &tria, aCrit );
8914 if ( aBadRate < aBestRate ) {
8916 aBestRate = aBadRate;
8921 // create new elements
8922 int aShapeId = FindShape( theFace );
8925 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8926 SMDS_MeshElement* newElem = 0;
8927 if ( iSplit == iBestQuad )
8928 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8933 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8935 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8936 myLastCreatedElems.Append(newElem);
8937 if ( aShapeId && newElem )
8938 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8941 // change nodes of theFace
8942 const SMDS_MeshNode* newNodes[ 4 ];
8943 newNodes[ 0 ] = linkNodes[ i1 ];
8944 newNodes[ 1 ] = linkNodes[ i2 ];
8945 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8946 newNodes[ 3 ] = nodes[ i4 ];
8947 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8948 const SMDS_MeshElement* newElem = 0;
8949 if (iSplit == iBestQuad)
8950 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8952 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8953 myLastCreatedElems.Append(newElem);
8954 if ( aShapeId && newElem )
8955 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8956 } // end if(!theFace->IsQuadratic())
8957 else { // theFace is quadratic
8958 // we have to split theFace on simple triangles and one simple quadrangle
8960 int nbshift = tmp*2;
8961 // shift nodes in nodes[] by nbshift
8963 for(i=0; i<nbshift; i++) {
8964 const SMDS_MeshNode* n = nodes[0];
8965 for(j=0; j<nbFaceNodes-1; j++) {
8966 nodes[j] = nodes[j+1];
8968 nodes[nbFaceNodes-1] = n;
8970 il1 = il1 - nbshift;
8971 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8972 // n0 n1 n2 n0 n1 n2
8973 // +-----+-----+ +-----+-----+
8982 // create new elements
8983 int aShapeId = FindShape( theFace );
8986 if(nbFaceNodes==6) { // quadratic triangle
8987 SMDS_MeshElement* newElem =
8988 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8989 myLastCreatedElems.Append(newElem);
8990 if ( aShapeId && newElem )
8991 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8992 if(theFace->IsMediumNode(nodes[il1])) {
8993 // create quadrangle
8994 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8995 myLastCreatedElems.Append(newElem);
8996 if ( aShapeId && newElem )
8997 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9003 // create quadrangle
9004 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9005 myLastCreatedElems.Append(newElem);
9006 if ( aShapeId && newElem )
9007 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9013 else { // nbFaceNodes==8 - quadratic quadrangle
9014 SMDS_MeshElement* newElem =
9015 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9016 myLastCreatedElems.Append(newElem);
9017 if ( aShapeId && newElem )
9018 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9019 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9020 myLastCreatedElems.Append(newElem);
9021 if ( aShapeId && newElem )
9022 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9023 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9024 myLastCreatedElems.Append(newElem);
9025 if ( aShapeId && newElem )
9026 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9027 if(theFace->IsMediumNode(nodes[il1])) {
9028 // create quadrangle
9029 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9030 myLastCreatedElems.Append(newElem);
9031 if ( aShapeId && newElem )
9032 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9038 // create quadrangle
9039 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9040 myLastCreatedElems.Append(newElem);
9041 if ( aShapeId && newElem )
9042 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9048 // create needed triangles using n1,n2,n3 and inserted nodes
9049 int nbn = 2 + aNodesToInsert.size();
9050 //const SMDS_MeshNode* aNodes[nbn];
9051 vector<const SMDS_MeshNode*> aNodes(nbn);
9052 aNodes[0] = nodes[n1];
9053 aNodes[nbn-1] = nodes[n2];
9054 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9055 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9056 aNodes[iNode++] = *nIt;
9058 for(i=1; i<nbn; i++) {
9059 SMDS_MeshElement* newElem =
9060 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9061 myLastCreatedElems.Append(newElem);
9062 if ( aShapeId && newElem )
9063 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9067 aMesh->RemoveElement(theFace);
9070 //=======================================================================
9071 //function : UpdateVolumes
9073 //=======================================================================
9074 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9075 const SMDS_MeshNode* theBetweenNode2,
9076 list<const SMDS_MeshNode*>& theNodesToInsert)
9078 myLastCreatedElems.Clear();
9079 myLastCreatedNodes.Clear();
9081 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9082 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9083 const SMDS_MeshElement* elem = invElemIt->next();
9085 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9086 SMDS_VolumeTool aVolume (elem);
9087 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9090 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9091 int iface, nbFaces = aVolume.NbFaces();
9092 vector<const SMDS_MeshNode *> poly_nodes;
9093 vector<int> quantities (nbFaces);
9095 for (iface = 0; iface < nbFaces; iface++) {
9096 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9097 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9098 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9100 for (int inode = 0; inode < nbFaceNodes; inode++) {
9101 poly_nodes.push_back(faceNodes[inode]);
9103 if (nbInserted == 0) {
9104 if (faceNodes[inode] == theBetweenNode1) {
9105 if (faceNodes[inode + 1] == theBetweenNode2) {
9106 nbInserted = theNodesToInsert.size();
9108 // add nodes to insert
9109 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9110 for (; nIt != theNodesToInsert.end(); nIt++) {
9111 poly_nodes.push_back(*nIt);
9115 else if (faceNodes[inode] == theBetweenNode2) {
9116 if (faceNodes[inode + 1] == theBetweenNode1) {
9117 nbInserted = theNodesToInsert.size();
9119 // add nodes to insert in reversed order
9120 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9122 for (; nIt != theNodesToInsert.begin(); nIt--) {
9123 poly_nodes.push_back(*nIt);
9125 poly_nodes.push_back(*nIt);
9132 quantities[iface] = nbFaceNodes + nbInserted;
9135 // Replace or update the volume
9136 SMESHDS_Mesh *aMesh = GetMeshDS();
9138 if (elem->IsPoly()) {
9139 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9143 int aShapeId = FindShape( elem );
9145 SMDS_MeshElement* newElem =
9146 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9147 myLastCreatedElems.Append(newElem);
9148 if (aShapeId && newElem)
9149 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9151 aMesh->RemoveElement(elem);
9156 //=======================================================================
9158 * \brief Convert elements contained in a submesh to quadratic
9159 * \retval int - nb of checked elements
9161 //=======================================================================
9163 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9164 SMESH_MesherHelper& theHelper,
9165 const bool theForce3d)
9168 if( !theSm ) return nbElem;
9170 vector<int> nbNodeInFaces;
9171 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9172 while(ElemItr->more())
9175 const SMDS_MeshElement* elem = ElemItr->next();
9176 if( !elem || elem->IsQuadratic() ) continue;
9178 int id = elem->GetID();
9179 //MESSAGE("elem " << id);
9180 id = 0; // get a free number for new elements
9181 int nbNodes = elem->NbNodes();
9182 SMDSAbs_ElementType aType = elem->GetType();
9184 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9185 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9186 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9188 const SMDS_MeshElement* NewElem = 0;
9194 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9202 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9205 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9208 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9213 case SMDSAbs_Volume :
9218 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9221 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9224 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9227 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9228 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9231 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9238 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9240 theSm->AddElement( NewElem );
9242 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9244 // if (!GetMeshDS()->isCompacted())
9245 // GetMeshDS()->compactMesh();
9249 //=======================================================================
9250 //function : ConvertToQuadratic
9252 //=======================================================================
9253 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9255 SMESHDS_Mesh* meshDS = GetMeshDS();
9257 SMESH_MesherHelper aHelper(*myMesh);
9258 aHelper.SetIsQuadratic( true );
9260 int nbCheckedElems = 0;
9261 if ( myMesh->HasShapeToMesh() )
9263 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9265 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9266 while ( smIt->more() ) {
9267 SMESH_subMesh* sm = smIt->next();
9268 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9269 aHelper.SetSubShape( sm->GetSubShape() );
9270 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9275 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9276 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9278 SMESHDS_SubMesh *smDS = 0;
9279 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9280 while(aEdgeItr->more())
9282 const SMDS_MeshEdge* edge = aEdgeItr->next();
9283 if(edge && !edge->IsQuadratic())
9285 int id = edge->GetID();
9286 //MESSAGE("edge->GetID() " << id);
9287 const SMDS_MeshNode* n1 = edge->GetNode(0);
9288 const SMDS_MeshNode* n2 = edge->GetNode(1);
9290 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9292 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9293 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9296 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9297 while(aFaceItr->more())
9299 const SMDS_MeshFace* face = aFaceItr->next();
9300 if(!face || face->IsQuadratic() ) continue;
9302 int id = face->GetID();
9303 int nbNodes = face->NbNodes();
9304 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9306 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9308 SMDS_MeshFace * NewFace = 0;
9312 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9315 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9318 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9320 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9322 vector<int> nbNodeInFaces;
9323 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9324 while(aVolumeItr->more())
9326 const SMDS_MeshVolume* volume = aVolumeItr->next();
9327 if(!volume || volume->IsQuadratic() ) continue;
9329 int id = volume->GetID();
9330 int nbNodes = volume->NbNodes();
9331 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9332 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9333 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9335 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9337 SMDS_MeshVolume * NewVolume = 0;
9341 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9342 nodes[3], id, theForce3d );
9345 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9346 nodes[3], nodes[4], id, theForce3d);
9349 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9350 nodes[3], nodes[4], nodes[5], id, theForce3d);
9353 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9354 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9357 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9359 ReplaceElemInGroups(volume, NewVolume, meshDS);
9363 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9364 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9365 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9366 aHelper.FixQuadraticElements();
9368 if (!GetMeshDS()->isCompacted())
9369 GetMeshDS()->compactMesh();
9372 //=======================================================================
9374 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9375 * \retval int - nb of checked elements
9377 //=======================================================================
9379 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9380 SMDS_ElemIteratorPtr theItr,
9381 const int theShapeID)
9384 SMESHDS_Mesh* meshDS = GetMeshDS();
9385 const bool notFromGroups = false;
9387 while( theItr->more() )
9389 const SMDS_MeshElement* elem = theItr->next();
9391 if( elem && elem->IsQuadratic())
9393 int id = elem->GetID();
9394 int nbNodes = elem->NbNodes();
9395 vector<const SMDS_MeshNode *> nodes, mediumNodes;
9396 nodes.reserve( nbNodes );
9397 mediumNodes.reserve( nbNodes );
9399 for(int i = 0; i < nbNodes; i++)
9401 const SMDS_MeshNode* n = elem->GetNode(i);
9403 if( elem->IsMediumNode( n ) )
9404 mediumNodes.push_back( n );
9406 nodes.push_back( n );
9408 if( nodes.empty() ) continue;
9409 SMDSAbs_ElementType aType = elem->GetType();
9411 //remove old quadratic element
9412 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9414 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9415 ReplaceElemInGroups(elem, NewElem, meshDS);
9416 if( theSm && NewElem )
9417 theSm->AddElement( NewElem );
9419 // remove medium nodes
9420 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9421 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9422 const SMDS_MeshNode* n = *nIt;
9423 if ( n->NbInverseElements() == 0 ) {
9424 if ( n->getshapeId() != theShapeID )
9425 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9426 ( n->getshapeId() ));
9428 meshDS->RemoveFreeNode( n, theSm );
9436 //=======================================================================
9437 //function : ConvertFromQuadratic
9439 //=======================================================================
9440 bool SMESH_MeshEditor::ConvertFromQuadratic()
9442 int nbCheckedElems = 0;
9443 if ( myMesh->HasShapeToMesh() )
9445 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9447 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9448 while ( smIt->more() ) {
9449 SMESH_subMesh* sm = smIt->next();
9450 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9451 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9457 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9458 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9460 SMESHDS_SubMesh *aSM = 0;
9461 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9467 //=======================================================================
9468 //function : SewSideElements
9470 //=======================================================================
9472 SMESH_MeshEditor::Sew_Error
9473 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9474 TIDSortedElemSet& theSide2,
9475 const SMDS_MeshNode* theFirstNode1,
9476 const SMDS_MeshNode* theFirstNode2,
9477 const SMDS_MeshNode* theSecondNode1,
9478 const SMDS_MeshNode* theSecondNode2)
9480 myLastCreatedElems.Clear();
9481 myLastCreatedNodes.Clear();
9483 MESSAGE ("::::SewSideElements()");
9484 if ( theSide1.size() != theSide2.size() )
9485 return SEW_DIFF_NB_OF_ELEMENTS;
9487 Sew_Error aResult = SEW_OK;
9489 // 1. Build set of faces representing each side
9490 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9491 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9493 // =======================================================================
9494 // 1. Build set of faces representing each side:
9495 // =======================================================================
9496 // a. build set of nodes belonging to faces
9497 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9498 // c. create temporary faces representing side of volumes if correspondent
9499 // face does not exist
9501 SMESHDS_Mesh* aMesh = GetMeshDS();
9502 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9503 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9504 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9505 set<const SMDS_MeshElement*> volSet1, volSet2;
9506 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9507 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9508 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9509 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9510 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9511 int iSide, iFace, iNode;
9513 list<const SMDS_MeshElement* > tempFaceList;
9514 for ( iSide = 0; iSide < 2; iSide++ ) {
9515 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9516 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9517 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9518 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9519 set<const SMDS_MeshElement*>::iterator vIt;
9520 TIDSortedElemSet::iterator eIt;
9521 set<const SMDS_MeshNode*>::iterator nIt;
9523 // check that given nodes belong to given elements
9524 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9525 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9526 int firstIndex = -1, secondIndex = -1;
9527 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9528 const SMDS_MeshElement* elem = *eIt;
9529 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9530 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9531 if ( firstIndex > -1 && secondIndex > -1 ) break;
9533 if ( firstIndex < 0 || secondIndex < 0 ) {
9534 // we can simply return until temporary faces created
9535 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9538 // -----------------------------------------------------------
9539 // 1a. Collect nodes of existing faces
9540 // and build set of face nodes in order to detect missing
9541 // faces corresponding to sides of volumes
9542 // -----------------------------------------------------------
9544 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9546 // loop on the given element of a side
9547 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9548 //const SMDS_MeshElement* elem = *eIt;
9549 const SMDS_MeshElement* elem = *eIt;
9550 if ( elem->GetType() == SMDSAbs_Face ) {
9551 faceSet->insert( elem );
9552 set <const SMDS_MeshNode*> faceNodeSet;
9553 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9554 while ( nodeIt->more() ) {
9555 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9556 nodeSet->insert( n );
9557 faceNodeSet.insert( n );
9559 setOfFaceNodeSet.insert( faceNodeSet );
9561 else if ( elem->GetType() == SMDSAbs_Volume )
9562 volSet->insert( elem );
9564 // ------------------------------------------------------------------------------
9565 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9566 // ------------------------------------------------------------------------------
9568 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9569 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9570 while ( fIt->more() ) { // loop on faces sharing a node
9571 const SMDS_MeshElement* f = fIt->next();
9572 if ( faceSet->find( f ) == faceSet->end() ) {
9573 // check if all nodes are in nodeSet and
9574 // complete setOfFaceNodeSet if they are
9575 set <const SMDS_MeshNode*> faceNodeSet;
9576 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9577 bool allInSet = true;
9578 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9579 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9580 if ( nodeSet->find( n ) == nodeSet->end() )
9583 faceNodeSet.insert( n );
9586 faceSet->insert( f );
9587 setOfFaceNodeSet.insert( faceNodeSet );
9593 // -------------------------------------------------------------------------
9594 // 1c. Create temporary faces representing sides of volumes if correspondent
9595 // face does not exist
9596 // -------------------------------------------------------------------------
9598 if ( !volSet->empty() ) {
9599 //int nodeSetSize = nodeSet->size();
9601 // loop on given volumes
9602 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9603 SMDS_VolumeTool vol (*vIt);
9604 // loop on volume faces: find free faces
9605 // --------------------------------------
9606 list<const SMDS_MeshElement* > freeFaceList;
9607 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9608 if ( !vol.IsFreeFace( iFace ))
9610 // check if there is already a face with same nodes in a face set
9611 const SMDS_MeshElement* aFreeFace = 0;
9612 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9613 int nbNodes = vol.NbFaceNodes( iFace );
9614 set <const SMDS_MeshNode*> faceNodeSet;
9615 vol.GetFaceNodes( iFace, faceNodeSet );
9616 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9618 // no such a face is given but it still can exist, check it
9619 if ( nbNodes == 3 ) {
9620 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9622 else if ( nbNodes == 4 ) {
9623 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9626 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9627 aFreeFace = aMesh->FindFace(poly_nodes);
9631 // create a temporary face
9632 if ( nbNodes == 3 ) {
9633 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9634 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9636 else if ( nbNodes == 4 ) {
9637 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9638 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9641 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9642 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9643 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9647 freeFaceList.push_back( aFreeFace );
9648 tempFaceList.push_back( aFreeFace );
9651 } // loop on faces of a volume
9653 // choose one of several free faces
9654 // --------------------------------------
9655 if ( freeFaceList.size() > 1 ) {
9656 // choose a face having max nb of nodes shared by other elems of a side
9657 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9658 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9659 while ( fIt != freeFaceList.end() ) { // loop on free faces
9660 int nbSharedNodes = 0;
9661 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9662 while ( nodeIt->more() ) { // loop on free face nodes
9663 const SMDS_MeshNode* n =
9664 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9665 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9666 while ( invElemIt->more() ) {
9667 const SMDS_MeshElement* e = invElemIt->next();
9668 if ( faceSet->find( e ) != faceSet->end() )
9670 if ( elemSet->find( e ) != elemSet->end() )
9674 if ( nbSharedNodes >= maxNbNodes ) {
9675 maxNbNodes = nbSharedNodes;
9679 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9681 if ( freeFaceList.size() > 1 )
9683 // could not choose one face, use another way
9684 // choose a face most close to the bary center of the opposite side
9685 gp_XYZ aBC( 0., 0., 0. );
9686 set <const SMDS_MeshNode*> addedNodes;
9687 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9688 eIt = elemSet2->begin();
9689 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9690 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9691 while ( nodeIt->more() ) { // loop on free face nodes
9692 const SMDS_MeshNode* n =
9693 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9694 if ( addedNodes.insert( n ).second )
9695 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9698 aBC /= addedNodes.size();
9699 double minDist = DBL_MAX;
9700 fIt = freeFaceList.begin();
9701 while ( fIt != freeFaceList.end() ) { // loop on free faces
9703 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9704 while ( nodeIt->more() ) { // loop on free face nodes
9705 const SMDS_MeshNode* n =
9706 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9707 gp_XYZ p( n->X(),n->Y(),n->Z() );
9708 dist += ( aBC - p ).SquareModulus();
9710 if ( dist < minDist ) {
9712 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9715 fIt = freeFaceList.erase( fIt++ );
9718 } // choose one of several free faces of a volume
9720 if ( freeFaceList.size() == 1 ) {
9721 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9722 faceSet->insert( aFreeFace );
9723 // complete a node set with nodes of a found free face
9724 // for ( iNode = 0; iNode < ; iNode++ )
9725 // nodeSet->insert( fNodes[ iNode ] );
9728 } // loop on volumes of a side
9730 // // complete a set of faces if new nodes in a nodeSet appeared
9731 // // ----------------------------------------------------------
9732 // if ( nodeSetSize != nodeSet->size() ) {
9733 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9734 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9735 // while ( fIt->more() ) { // loop on faces sharing a node
9736 // const SMDS_MeshElement* f = fIt->next();
9737 // if ( faceSet->find( f ) == faceSet->end() ) {
9738 // // check if all nodes are in nodeSet and
9739 // // complete setOfFaceNodeSet if they are
9740 // set <const SMDS_MeshNode*> faceNodeSet;
9741 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9742 // bool allInSet = true;
9743 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9744 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9745 // if ( nodeSet->find( n ) == nodeSet->end() )
9746 // allInSet = false;
9748 // faceNodeSet.insert( n );
9750 // if ( allInSet ) {
9751 // faceSet->insert( f );
9752 // setOfFaceNodeSet.insert( faceNodeSet );
9758 } // Create temporary faces, if there are volumes given
9761 if ( faceSet1.size() != faceSet2.size() ) {
9762 // delete temporary faces: they are in reverseElements of actual nodes
9763 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9764 // while ( tmpFaceIt->more() )
9765 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9766 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9767 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9768 // aMesh->RemoveElement(*tmpFaceIt);
9769 MESSAGE("Diff nb of faces");
9770 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9773 // ============================================================
9774 // 2. Find nodes to merge:
9775 // bind a node to remove to a node to put instead
9776 // ============================================================
9778 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9779 if ( theFirstNode1 != theFirstNode2 )
9780 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9781 if ( theSecondNode1 != theSecondNode2 )
9782 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9784 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9785 set< long > linkIdSet; // links to process
9786 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9788 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9789 list< NLink > linkList[2];
9790 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9791 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9792 // loop on links in linkList; find faces by links and append links
9793 // of the found faces to linkList
9794 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9795 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9796 NLink link[] = { *linkIt[0], *linkIt[1] };
9797 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9798 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9801 // by links, find faces in the face sets,
9802 // and find indices of link nodes in the found faces;
9803 // in a face set, there is only one or no face sharing a link
9804 // ---------------------------------------------------------------
9806 const SMDS_MeshElement* face[] = { 0, 0 };
9807 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9808 vector<const SMDS_MeshNode*> fnodes1(9);
9809 vector<const SMDS_MeshNode*> fnodes2(9);
9810 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9811 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9812 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9813 int iLinkNode[2][2];
9814 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9815 const SMDS_MeshNode* n1 = link[iSide].first;
9816 const SMDS_MeshNode* n2 = link[iSide].second;
9817 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9818 set< const SMDS_MeshElement* > fMap;
9819 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9820 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9821 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9822 while ( fIt->more() ) { // loop on faces sharing a node
9823 const SMDS_MeshElement* f = fIt->next();
9824 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9825 ! fMap.insert( f ).second ) // f encounters twice
9827 if ( face[ iSide ] ) {
9828 MESSAGE( "2 faces per link " );
9829 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9833 faceSet->erase( f );
9834 // get face nodes and find ones of a link
9839 fnodes1.resize(f->NbNodes()+1);
9840 notLinkNodes1.resize(f->NbNodes()-2);
9843 fnodes2.resize(f->NbNodes()+1);
9844 notLinkNodes2.resize(f->NbNodes()-2);
9847 if(!f->IsQuadratic()) {
9848 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9849 while ( nIt->more() ) {
9850 const SMDS_MeshNode* n =
9851 static_cast<const SMDS_MeshNode*>( nIt->next() );
9853 iLinkNode[ iSide ][ 0 ] = iNode;
9855 else if ( n == n2 ) {
9856 iLinkNode[ iSide ][ 1 ] = iNode;
9858 //else if ( notLinkNodes[ iSide ][ 0 ] )
9859 // notLinkNodes[ iSide ][ 1 ] = n;
9861 // notLinkNodes[ iSide ][ 0 ] = n;
9865 notLinkNodes1[nbl] = n;
9866 //notLinkNodes1.push_back(n);
9868 notLinkNodes2[nbl] = n;
9869 //notLinkNodes2.push_back(n);
9871 //faceNodes[ iSide ][ iNode++ ] = n;
9873 fnodes1[iNode++] = n;
9876 fnodes2[iNode++] = n;
9880 else { // f->IsQuadratic()
9881 const SMDS_VtkFace* F =
9882 dynamic_cast<const SMDS_VtkFace*>(f);
9883 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9884 // use special nodes iterator
9885 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9886 while ( anIter->more() ) {
9887 const SMDS_MeshNode* n =
9888 static_cast<const SMDS_MeshNode*>( anIter->next() );
9890 iLinkNode[ iSide ][ 0 ] = iNode;
9892 else if ( n == n2 ) {
9893 iLinkNode[ iSide ][ 1 ] = iNode;
9898 notLinkNodes1[nbl] = n;
9901 notLinkNodes2[nbl] = n;
9905 fnodes1[iNode++] = n;
9908 fnodes2[iNode++] = n;
9912 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9914 fnodes1[iNode] = fnodes1[0];
9917 fnodes2[iNode] = fnodes1[0];
9924 // check similarity of elements of the sides
9925 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9926 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9927 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9928 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9931 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9933 break; // do not return because it s necessary to remove tmp faces
9936 // set nodes to merge
9937 // -------------------
9939 if ( face[0] && face[1] ) {
9940 int nbNodes = face[0]->NbNodes();
9941 if ( nbNodes != face[1]->NbNodes() ) {
9942 MESSAGE("Diff nb of face nodes");
9943 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9944 break; // do not return because it s necessary to remove tmp faces
9946 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9947 if ( nbNodes == 3 ) {
9948 //nReplaceMap.insert( TNodeNodeMap::value_type
9949 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9950 nReplaceMap.insert( TNodeNodeMap::value_type
9951 ( notLinkNodes1[0], notLinkNodes2[0] ));
9954 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9955 // analyse link orientation in faces
9956 int i1 = iLinkNode[ iSide ][ 0 ];
9957 int i2 = iLinkNode[ iSide ][ 1 ];
9958 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9959 // if notLinkNodes are the first and the last ones, then
9960 // their order does not correspond to the link orientation
9961 if (( i1 == 1 && i2 == 2 ) ||
9962 ( i1 == 2 && i2 == 1 ))
9963 reverse[ iSide ] = !reverse[ iSide ];
9965 if ( reverse[0] == reverse[1] ) {
9966 //nReplaceMap.insert( TNodeNodeMap::value_type
9967 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9968 //nReplaceMap.insert( TNodeNodeMap::value_type
9969 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9970 for(int nn=0; nn<nbNodes-2; nn++) {
9971 nReplaceMap.insert( TNodeNodeMap::value_type
9972 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9976 //nReplaceMap.insert( TNodeNodeMap::value_type
9977 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9978 //nReplaceMap.insert( TNodeNodeMap::value_type
9979 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9980 for(int nn=0; nn<nbNodes-2; nn++) {
9981 nReplaceMap.insert( TNodeNodeMap::value_type
9982 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9987 // add other links of the faces to linkList
9988 // -----------------------------------------
9990 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9991 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9992 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9993 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9994 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9995 if ( !iter_isnew.second ) { // already in a set: no need to process
9996 linkIdSet.erase( iter_isnew.first );
9998 else // new in set == encountered for the first time: add
10000 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10001 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10002 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10003 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10004 linkList[0].push_back ( NLink( n1, n2 ));
10005 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10009 } // loop on link lists
10011 if ( aResult == SEW_OK &&
10012 ( linkIt[0] != linkList[0].end() ||
10013 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10014 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10015 " " << (faceSetPtr[1]->empty()));
10016 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10019 // ====================================================================
10020 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10021 // ====================================================================
10023 // delete temporary faces: they are in reverseElements of actual nodes
10024 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10025 // while ( tmpFaceIt->more() )
10026 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10027 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10028 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10029 // aMesh->RemoveElement(*tmpFaceIt);
10031 if ( aResult != SEW_OK)
10034 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10035 // loop on nodes replacement map
10036 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10037 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10038 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10039 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10040 nodeIDsToRemove.push_back( nToRemove->GetID() );
10041 // loop on elements sharing nToRemove
10042 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10043 while ( invElemIt->more() ) {
10044 const SMDS_MeshElement* e = invElemIt->next();
10045 // get a new suite of nodes: make replacement
10046 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10047 vector< const SMDS_MeshNode*> nodes( nbNodes );
10048 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10049 while ( nIt->more() ) {
10050 const SMDS_MeshNode* n =
10051 static_cast<const SMDS_MeshNode*>( nIt->next() );
10052 nnIt = nReplaceMap.find( n );
10053 if ( nnIt != nReplaceMap.end() ) {
10055 n = (*nnIt).second;
10059 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10060 // elemIDsToRemove.push_back( e->GetID() );
10064 SMDSAbs_ElementType etyp = e->GetType();
10065 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10068 myLastCreatedElems.Append(newElem);
10069 AddToSameGroups(newElem, e, aMesh);
10070 int aShapeId = e->getshapeId();
10073 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10076 aMesh->RemoveElement(e);
10081 Remove( nodeIDsToRemove, true );
10086 //================================================================================
10088 * \brief Find corresponding nodes in two sets of faces
10089 * \param theSide1 - first face set
10090 * \param theSide2 - second first face
10091 * \param theFirstNode1 - a boundary node of set 1
10092 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10093 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10094 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10095 * \param nReplaceMap - output map of corresponding nodes
10096 * \retval bool - is a success or not
10098 //================================================================================
10101 //#define DEBUG_MATCHING_NODES
10104 SMESH_MeshEditor::Sew_Error
10105 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10106 set<const SMDS_MeshElement*>& theSide2,
10107 const SMDS_MeshNode* theFirstNode1,
10108 const SMDS_MeshNode* theFirstNode2,
10109 const SMDS_MeshNode* theSecondNode1,
10110 const SMDS_MeshNode* theSecondNode2,
10111 TNodeNodeMap & nReplaceMap)
10113 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10115 nReplaceMap.clear();
10116 if ( theFirstNode1 != theFirstNode2 )
10117 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10118 if ( theSecondNode1 != theSecondNode2 )
10119 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10121 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10122 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10124 list< NLink > linkList[2];
10125 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10126 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10128 // loop on links in linkList; find faces by links and append links
10129 // of the found faces to linkList
10130 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10131 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10132 NLink link[] = { *linkIt[0], *linkIt[1] };
10133 if ( linkSet.find( link[0] ) == linkSet.end() )
10136 // by links, find faces in the face sets,
10137 // and find indices of link nodes in the found faces;
10138 // in a face set, there is only one or no face sharing a link
10139 // ---------------------------------------------------------------
10141 const SMDS_MeshElement* face[] = { 0, 0 };
10142 list<const SMDS_MeshNode*> notLinkNodes[2];
10143 //bool reverse[] = { false, false }; // order of notLinkNodes
10145 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10147 const SMDS_MeshNode* n1 = link[iSide].first;
10148 const SMDS_MeshNode* n2 = link[iSide].second;
10149 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10150 set< const SMDS_MeshElement* > facesOfNode1;
10151 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10153 // during a loop of the first node, we find all faces around n1,
10154 // during a loop of the second node, we find one face sharing both n1 and n2
10155 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10156 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10157 while ( fIt->more() ) { // loop on faces sharing a node
10158 const SMDS_MeshElement* f = fIt->next();
10159 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10160 ! facesOfNode1.insert( f ).second ) // f encounters twice
10162 if ( face[ iSide ] ) {
10163 MESSAGE( "2 faces per link " );
10164 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10167 faceSet->erase( f );
10169 // get not link nodes
10170 int nbN = f->NbNodes();
10171 if ( f->IsQuadratic() )
10173 nbNodes[ iSide ] = nbN;
10174 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10175 int i1 = f->GetNodeIndex( n1 );
10176 int i2 = f->GetNodeIndex( n2 );
10177 int iEnd = nbN, iBeg = -1, iDelta = 1;
10178 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10180 std::swap( iEnd, iBeg ); iDelta = -1;
10185 if ( i == iEnd ) i = iBeg + iDelta;
10186 if ( i == i1 ) break;
10187 nodes.push_back ( f->GetNode( i ) );
10193 // check similarity of elements of the sides
10194 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10195 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10196 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10197 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10200 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10204 // set nodes to merge
10205 // -------------------
10207 if ( face[0] && face[1] ) {
10208 if ( nbNodes[0] != nbNodes[1] ) {
10209 MESSAGE("Diff nb of face nodes");
10210 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10212 #ifdef DEBUG_MATCHING_NODES
10213 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10214 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10215 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10217 int nbN = nbNodes[0];
10219 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10220 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10221 for ( int i = 0 ; i < nbN - 2; ++i ) {
10222 #ifdef DEBUG_MATCHING_NODES
10223 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10225 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10229 // add other links of the face 1 to linkList
10230 // -----------------------------------------
10232 const SMDS_MeshElement* f0 = face[0];
10233 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10234 for ( int i = 0; i < nbN; i++ )
10236 const SMDS_MeshNode* n2 = f0->GetNode( i );
10237 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10238 linkSet.insert( SMESH_TLink( n1, n2 ));
10239 if ( !iter_isnew.second ) { // already in a set: no need to process
10240 linkSet.erase( iter_isnew.first );
10242 else // new in set == encountered for the first time: add
10244 #ifdef DEBUG_MATCHING_NODES
10245 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10246 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10248 linkList[0].push_back ( NLink( n1, n2 ));
10249 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10254 } // loop on link lists
10259 //================================================================================
10261 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10262 \param theElems - the list of elements (edges or faces) to be replicated
10263 The nodes for duplication could be found from these elements
10264 \param theNodesNot - list of nodes to NOT replicate
10265 \param theAffectedElems - the list of elements (cells and edges) to which the
10266 replicated nodes should be associated to.
10267 \return TRUE if operation has been completed successfully, FALSE otherwise
10269 //================================================================================
10271 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10272 const TIDSortedElemSet& theNodesNot,
10273 const TIDSortedElemSet& theAffectedElems )
10275 myLastCreatedElems.Clear();
10276 myLastCreatedNodes.Clear();
10278 if ( theElems.size() == 0 )
10281 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10286 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10287 // duplicate elements and nodes
10288 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10289 // replce nodes by duplications
10290 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10294 //================================================================================
10296 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10297 \param theMeshDS - mesh instance
10298 \param theElems - the elements replicated or modified (nodes should be changed)
10299 \param theNodesNot - nodes to NOT replicate
10300 \param theNodeNodeMap - relation of old node to new created node
10301 \param theIsDoubleElem - flag os to replicate element or modify
10302 \return TRUE if operation has been completed successfully, FALSE otherwise
10304 //================================================================================
10306 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10307 const TIDSortedElemSet& theElems,
10308 const TIDSortedElemSet& theNodesNot,
10309 std::map< const SMDS_MeshNode*,
10310 const SMDS_MeshNode* >& theNodeNodeMap,
10311 const bool theIsDoubleElem )
10313 MESSAGE("doubleNodes");
10314 // iterate on through element and duplicate them (by nodes duplication)
10316 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10317 for ( ; elemItr != theElems.end(); ++elemItr )
10319 const SMDS_MeshElement* anElem = *elemItr;
10323 bool isDuplicate = false;
10324 // duplicate nodes to duplicate element
10325 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10326 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10328 while ( anIter->more() )
10331 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10332 SMDS_MeshNode* aNewNode = aCurrNode;
10333 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10334 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10335 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10338 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10339 theNodeNodeMap[ aCurrNode ] = aNewNode;
10340 myLastCreatedNodes.Append( aNewNode );
10342 isDuplicate |= (aCurrNode != aNewNode);
10343 newNodes[ ind++ ] = aNewNode;
10345 if ( !isDuplicate )
10348 if ( theIsDoubleElem )
10349 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10352 MESSAGE("ChangeElementNodes");
10353 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10360 //================================================================================
10362 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10363 \param theNodes - identifiers of nodes to be doubled
10364 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10365 nodes. If list of element identifiers is empty then nodes are doubled but
10366 they not assigned to elements
10367 \return TRUE if operation has been completed successfully, FALSE otherwise
10369 //================================================================================
10371 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10372 const std::list< int >& theListOfModifiedElems )
10374 MESSAGE("DoubleNodes");
10375 myLastCreatedElems.Clear();
10376 myLastCreatedNodes.Clear();
10378 if ( theListOfNodes.size() == 0 )
10381 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10385 // iterate through nodes and duplicate them
10387 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10389 std::list< int >::const_iterator aNodeIter;
10390 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10392 int aCurr = *aNodeIter;
10393 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10399 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10402 anOldNodeToNewNode[ aNode ] = aNewNode;
10403 myLastCreatedNodes.Append( aNewNode );
10407 // Create map of new nodes for modified elements
10409 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10411 std::list< int >::const_iterator anElemIter;
10412 for ( anElemIter = theListOfModifiedElems.begin();
10413 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10415 int aCurr = *anElemIter;
10416 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10420 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10422 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10424 while ( anIter->more() )
10426 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10427 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10429 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10430 aNodeArr[ ind++ ] = aNewNode;
10433 aNodeArr[ ind++ ] = aCurrNode;
10435 anElemToNodes[ anElem ] = aNodeArr;
10438 // Change nodes of elements
10440 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10441 anElemToNodesIter = anElemToNodes.begin();
10442 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10444 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10445 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10448 MESSAGE("ChangeElementNodes");
10449 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10458 //================================================================================
10460 \brief Check if element located inside shape
10461 \return TRUE if IN or ON shape, FALSE otherwise
10463 //================================================================================
10465 template<class Classifier>
10466 bool isInside(const SMDS_MeshElement* theElem,
10467 Classifier& theClassifier,
10468 const double theTol)
10470 gp_XYZ centerXYZ (0, 0, 0);
10471 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10472 while (aNodeItr->more())
10473 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10475 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10476 theClassifier.Perform(aPnt, theTol);
10477 TopAbs_State aState = theClassifier.State();
10478 return (aState == TopAbs_IN || aState == TopAbs_ON );
10481 //================================================================================
10483 * \brief Classifier of the 3D point on the TopoDS_Face
10484 * with interaface suitable for isInside()
10486 //================================================================================
10488 struct _FaceClassifier
10490 Extrema_ExtPS _extremum;
10491 BRepAdaptor_Surface _surface;
10492 TopAbs_State _state;
10494 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10496 _extremum.Initialize( _surface,
10497 _surface.FirstUParameter(), _surface.LastUParameter(),
10498 _surface.FirstVParameter(), _surface.LastVParameter(),
10499 _surface.Tolerance(), _surface.Tolerance() );
10501 void Perform(const gp_Pnt& aPnt, double theTol)
10503 _state = TopAbs_OUT;
10504 _extremum.Perform(aPnt);
10505 if ( _extremum.IsDone() )
10506 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10507 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10509 TopAbs_State State() const
10516 //================================================================================
10518 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10519 \param theElems - group of of elements (edges or faces) to be replicated
10520 \param theNodesNot - group of nodes not to replicate
10521 \param theShape - shape to detect affected elements (element which geometric center
10522 located on or inside shape).
10523 The replicated nodes should be associated to affected elements.
10524 \return TRUE if operation has been completed successfully, FALSE otherwise
10526 //================================================================================
10528 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10529 const TIDSortedElemSet& theNodesNot,
10530 const TopoDS_Shape& theShape )
10532 if ( theShape.IsNull() )
10535 const double aTol = Precision::Confusion();
10536 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10537 auto_ptr<_FaceClassifier> aFaceClassifier;
10538 if ( theShape.ShapeType() == TopAbs_SOLID )
10540 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10541 bsc3d->PerformInfinitePoint(aTol);
10543 else if (theShape.ShapeType() == TopAbs_FACE )
10545 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10548 // iterates on indicated elements and get elements by back references from their nodes
10549 TIDSortedElemSet anAffected;
10550 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10551 for ( ; elemItr != theElems.end(); ++elemItr )
10553 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10557 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10558 while ( nodeItr->more() )
10560 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10561 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10563 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10564 while ( backElemItr->more() )
10566 const SMDS_MeshElement* curElem = backElemItr->next();
10567 if ( curElem && theElems.find(curElem) == theElems.end() &&
10569 isInside( curElem, *bsc3d, aTol ) :
10570 isInside( curElem, *aFaceClassifier, aTol )))
10571 anAffected.insert( curElem );
10575 return DoubleNodes( theElems, theNodesNot, anAffected );
10579 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10580 * The list of groups must describe a partition of the mesh volumes.
10581 * The nodes of the internal faces at the boundaries of the groups are doubled.
10582 * In option, the internal faces are replaced by flat elements.
10583 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10584 * @param theElems - list of groups of volumes, where a group of volume is a set of
10585 * SMDS_MeshElements sorted by Id.
10586 * @param createJointElems - if TRUE, create the elements
10587 * @return TRUE if operation has been completed successfully, FALSE otherwise
10589 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10590 bool createJointElems)
10592 MESSAGE("------------------------------------------------------");
10593 MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10594 MESSAGE("------------------------------------------------------");
10596 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10597 meshDS->BuildDownWardConnectivity(false);
10599 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10601 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10602 // build the list of nodes shared by 2 or more domains, with their domain indexes
10604 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10605 std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
10606 faceDomains.clear();
10607 nodeDomains.clear();
10608 std::map<int,int> emptyMap;
10611 for (int idom = 0; idom < theElems.size(); idom++)
10614 // --- build a map (face to duplicate --> volume to modify)
10615 // with all the faces shared by 2 domains (group of elements)
10616 // and corresponding volume of this domain, for each shared face.
10617 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10619 const TIDSortedElemSet& domain = theElems[idom];
10620 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10621 for (; elemItr != domain.end(); ++elemItr)
10623 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10626 int vtkId = anElem->getVtkId();
10627 int neighborsVtkIds[NBMAXNEIGHBORS];
10628 int downIds[NBMAXNEIGHBORS];
10629 unsigned char downTypes[NBMAXNEIGHBORS];
10630 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10631 for (int n = 0; n < nbNeighbors; n++)
10633 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10634 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10635 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10637 DownIdType face(downIds[n], downTypes[n]);
10638 if (!faceDomains.count(face))
10639 faceDomains[face] = emptyMap; // create an empty entry for face
10640 if (!faceDomains[face].count(idom))
10642 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10649 MESSAGE("Number of shared faces " << faceDomains.size());
10651 // --- for each shared face, get the nodes
10652 // for each node, for each domain of the face, create a clone of the node
10654 std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10655 for( ; itface != faceDomains.end();++itface )
10657 DownIdType face = itface->first;
10658 std::map<int,int> domvol = itface->second;
10659 std::set<int> oldNodes;
10661 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10662 std::set<int>::iterator itn = oldNodes.begin();
10663 for (;itn != oldNodes.end(); ++itn)
10666 if (!nodeDomains.count(oldId))
10667 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10668 std::map<int,int>::iterator itdom = domvol.begin();
10669 for(; itdom != domvol.end(); ++itdom)
10671 int idom = itdom->first;
10672 if ( nodeDomains[oldId].empty() )
10673 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10676 double *coords = grid->GetPoint(oldId);
10677 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10678 int newId = newNode->getVtkId();
10679 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10685 // --- iterate on shared faces (volumes to modify, face to extrude)
10686 // get node id's of the face (id SMDS = id VTK)
10687 // create flat element with old and new nodes if requested
10689 if (createJointElems)
10691 itface = faceDomains.begin();
10692 for( ; itface != faceDomains.end();++itface )
10694 DownIdType face = itface->first;
10695 std::set<int> oldNodes;
10696 std::set<int>::iterator itn;
10698 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10699 std::map<int,int> localClonedNodeIds;
10701 std::map<int,int> domvol = itface->second;
10702 std::map<int,int>::iterator itdom = domvol.begin();
10703 int dom1 = itdom->first;
10704 int vtkVolId = itdom->second;
10706 int dom2 = itdom->first;
10708 localClonedNodeIds.clear();
10709 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10713 if (nodeDomains[oldId].count(dom1))
10714 refid = nodeDomains[oldId][dom1];
10716 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10718 if (nodeDomains[oldId].count(dom2))
10719 newid = nodeDomains[oldId][dom2];
10721 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10722 localClonedNodeIds[oldId] = newid;
10724 meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10728 // --- iterate on shared faces (volumes to modify, face to extrude)
10729 // get node id's of the face
10730 // replace old nodes by new nodes in volumes, and update inverse connectivity
10732 itface = faceDomains.begin();
10733 for( ; itface != faceDomains.end();++itface )
10735 DownIdType face = itface->first;
10736 std::set<int> oldNodes;
10737 std::set<int>::iterator itn;
10739 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10740 std::map<int,int> localClonedNodeIds;
10742 std::map<int,int> domvol = itface->second;
10743 std::map<int,int>::iterator itdom = domvol.begin();
10744 for(; itdom != domvol.end(); ++itdom)
10746 int idom = itdom->first;
10747 int vtkVolId = itdom->second;
10748 localClonedNodeIds.clear();
10749 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10752 if (nodeDomains[oldId].count(idom))
10753 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10755 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10758 grid->BuildLinks();
10760 // TODO replace also old nodes by new nodes in faces and edges
10766 //================================================================================
10768 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10769 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10770 * \return TRUE if operation has been completed successfully, FALSE otherwise
10772 //================================================================================
10774 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10776 // iterates on volume elements and detect all free faces on them
10777 SMESHDS_Mesh* aMesh = GetMeshDS();
10780 //bool res = false;
10781 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10782 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10785 const SMDS_MeshVolume* volume = vIt->next();
10786 SMDS_VolumeTool vTool( volume );
10787 vTool.SetExternalNormal();
10788 const bool isPoly = volume->IsPoly();
10789 const bool isQuad = volume->IsQuadratic();
10790 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10792 if (!vTool.IsFreeFace(iface))
10795 vector<const SMDS_MeshNode *> nodes;
10796 int nbFaceNodes = vTool.NbFaceNodes(iface);
10797 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10799 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10800 nodes.push_back(faceNodes[inode]);
10802 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10803 nodes.push_back(faceNodes[inode]);
10805 // add new face based on volume nodes
10806 if (aMesh->FindFace( nodes ) ) {
10808 continue; // face already exsist
10810 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10814 return ( nbFree==(nbExisted+nbCreated) );
10819 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10821 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10823 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10826 //================================================================================
10828 * \brief Creates missing boundary elements
10829 * \param elements - elements whose boundary is to be checked
10830 * \param dimension - defines type of boundary elements to create
10831 * \param group - a group to store created boundary elements in
10832 * \param targetMesh - a mesh to store created boundary elements in
10833 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10834 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10835 * boundary elements will be copied into the targetMesh
10837 //================================================================================
10839 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10840 Bnd_Dimension dimension,
10841 SMESH_Group* group/*=0*/,
10842 SMESH_Mesh* targetMesh/*=0*/,
10843 bool toCopyElements/*=false*/,
10844 bool toCopyExistingBondary/*=false*/)
10846 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10847 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10848 // hope that all elements are of the same type, do not check them all
10849 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10850 throw SALOME_Exception(LOCALIZED("wrong element type"));
10853 toCopyElements = toCopyExistingBondary = false;
10855 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10856 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10858 SMDS_VolumeTool vTool;
10859 TIDSortedElemSet emptySet, avoidSet;
10862 typedef vector<const SMDS_MeshNode*> TConnectivity;
10864 SMDS_ElemIteratorPtr eIt;
10865 if (elements.empty())
10866 eIt = aMesh->elementsIterator(elemType);
10868 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10870 while (eIt->more())
10872 const SMDS_MeshElement* elem = eIt->next();
10873 const int iQuad = elem->IsQuadratic();
10875 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10876 vector<const SMDS_MeshElement*> presentBndElems;
10877 vector<TConnectivity> missingBndElems;
10878 TConnectivity nodes;
10879 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10881 vTool.SetExternalNormal();
10882 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10884 if (!vTool.IsFreeFace(iface))
10886 int nbFaceNodes = vTool.NbFaceNodes(iface);
10887 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10888 if ( missType == SMDSAbs_Edge ) // boundary edges
10890 nodes.resize( 2+iQuad );
10891 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10893 for ( int j = 0; j < nodes.size(); ++j )
10895 if ( const SMDS_MeshElement* edge =
10896 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10897 presentBndElems.push_back( edge );
10899 missingBndElems.push_back( nodes );
10902 else // boundary face
10905 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10906 nodes.push_back( nn[inode] );
10908 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10909 nodes.push_back( nn[inode] );
10911 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10912 presentBndElems.push_back( f );
10914 missingBndElems.push_back( nodes );
10918 else // elem is a face ------------------------------------------
10920 avoidSet.clear(), avoidSet.insert( elem );
10921 int nbNodes = elem->NbCornerNodes();
10922 nodes.resize( 2 /*+ iQuad*/);
10923 for ( int i = 0; i < nbNodes; i++ )
10925 nodes[0] = elem->GetNode(i);
10926 nodes[1] = elem->GetNode((i+1)%nbNodes);
10927 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10928 continue; // not free link
10931 //nodes[2] = elem->GetNode( i + nbNodes );
10932 if ( const SMDS_MeshElement* edge =
10933 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10934 presentBndElems.push_back( edge );
10936 missingBndElems.push_back( nodes );
10940 // 2. Add missing boundary elements
10941 if ( targetMesh != myMesh )
10942 // instead of making a map of nodes in this mesh and targetMesh,
10943 // we create nodes with same IDs. We can renumber them later, if needed
10944 for ( int i = 0; i < missingBndElems.size(); ++i )
10946 TConnectivity& srcNodes = missingBndElems[i];
10947 TConnectivity nodes( srcNodes.size() );
10948 for ( inode = 0; inode < nodes.size(); ++inode )
10949 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10950 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10953 for ( int i = 0; i < missingBndElems.size(); ++i )
10955 TConnectivity& nodes = missingBndElems[i];
10956 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10959 // 3. Copy present boundary elements
10960 if ( toCopyExistingBondary )
10961 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10963 const SMDS_MeshElement* e = presentBndElems[i];
10964 TConnectivity nodes( e->NbNodes() );
10965 for ( inode = 0; inode < nodes.size(); ++inode )
10966 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10967 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10968 // leave only missing elements in tgtEditor.myLastCreatedElems
10969 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10971 } // loop on given elements
10973 // 4. Fill group with missing boundary elements
10976 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10977 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10978 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10980 tgtEditor.myLastCreatedElems.Clear();
10982 // 5. Copy given elements
10983 if ( toCopyElements )
10985 if (elements.empty())
10986 eIt = aMesh->elementsIterator(elemType);
10988 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10989 while (eIt->more())
10991 const SMDS_MeshElement* elem = eIt->next();
10992 TConnectivity nodes( elem->NbNodes() );
10993 for ( inode = 0; inode < nodes.size(); ++inode )
10994 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10995 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10997 tgtEditor.myLastCreatedElems.Clear();