1 // Copyright (C) 2007-2013 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 // File : SMESH_MeshEditor.cxx
24 // Created : Mon Apr 12 16:10:22 2004
25 // Author : Edward AGAPOV (eap)
27 #include "SMESH_MeshEditor.hxx"
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.hxx"
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MeshAlgos.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
50 #include <Basics_OCCTVersion.hxx>
52 #include "utilities.h"
54 #include <BRepAdaptor_Surface.hxx>
55 #include <BRepBuilderAPI_MakeEdge.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <GeomAdaptor_Surface.hxx>
64 #include <Geom_Curve.hxx>
65 #include <Geom_Surface.hxx>
66 #include <Precision.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68 #include <TopAbs_State.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_ListIteratorOfListOfShape.hxx>
72 #include <TopTools_ListOfShape.hxx>
73 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopoDS_Face.hxx>
76 #include <TopoDS_Solid.hxx>
82 #include <gp_Trsf.hxx>
96 #include <boost/tuple/tuple.hpp>
98 #include <Standard_Failure.hxx>
99 #include <Standard_ErrorHandler.hxx>
101 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
104 using namespace SMESH::Controls;
108 template < class ELEM_SET >
109 SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
111 typedef SMDS_SetIterator
112 < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
113 return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
117 //=======================================================================
118 //function : SMESH_MeshEditor
120 //=======================================================================
122 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
123 :myMesh( theMesh ) // theMesh may be NULL
127 //================================================================================
129 * \brief Clears myLastCreatedNodes and myLastCreatedElems
131 //================================================================================
133 void SMESH_MeshEditor::CrearLastCreated()
135 myLastCreatedNodes.Clear();
136 myLastCreatedElems.Clear();
140 //=======================================================================
144 //=======================================================================
147 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
148 const SMDSAbs_ElementType type,
151 const double ballDiameter)
153 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
154 SMDS_MeshElement* e = 0;
155 int nbnode = node.size();
156 SMESHDS_Mesh* mesh = GetMeshDS();
161 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
162 else e = mesh->AddFace (node[0], node[1], node[2] );
164 else if (nbnode == 4) {
165 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
166 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
168 else if (nbnode == 6) {
169 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
170 node[4], node[5], ID);
171 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
174 else if (nbnode == 7) {
175 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
176 node[4], node[5], node[6], ID);
177 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
178 node[4], node[5], node[6] );
180 else if (nbnode == 8) {
181 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
182 node[4], node[5], node[6], node[7], ID);
183 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
184 node[4], node[5], node[6], node[7] );
186 else if (nbnode == 9) {
187 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
188 node[4], node[5], node[6], node[7], node[8], ID);
189 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
190 node[4], node[5], node[6], node[7], node[8] );
193 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
194 else e = mesh->AddPolygonalFace (node );
201 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
202 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
204 else if (nbnode == 5) {
205 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
210 else if (nbnode == 6) {
211 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212 node[4], node[5], ID);
213 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
216 else if (nbnode == 8) {
217 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
218 node[4], node[5], node[6], node[7], ID);
219 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
220 node[4], node[5], node[6], node[7] );
222 else if (nbnode == 10) {
223 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
224 node[4], node[5], node[6], node[7],
225 node[8], node[9], ID);
226 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
227 node[4], node[5], node[6], node[7],
230 else if (nbnode == 12) {
231 if ( ID >= 1 ) 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], ID);
234 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
235 node[4], node[5], node[6], node[7],
236 node[8], node[9], node[10], node[11] );
238 else if (nbnode == 13) {
239 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
240 node[4], node[5], node[6], node[7],
241 node[8], node[9], node[10],node[11],
243 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
244 node[4], node[5], node[6], node[7],
245 node[8], node[9], node[10],node[11],
248 else if (nbnode == 15) {
249 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
250 node[4], node[5], node[6], node[7],
251 node[8], node[9], node[10],node[11],
252 node[12],node[13],node[14],ID);
253 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
254 node[4], node[5], node[6], node[7],
255 node[8], node[9], node[10],node[11],
256 node[12],node[13],node[14] );
258 else if (nbnode == 20) {
259 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
260 node[4], node[5], node[6], node[7],
261 node[8], node[9], node[10],node[11],
262 node[12],node[13],node[14],node[15],
263 node[16],node[17],node[18],node[19],ID);
264 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
265 node[4], node[5], node[6], node[7],
266 node[8], node[9], node[10],node[11],
267 node[12],node[13],node[14],node[15],
268 node[16],node[17],node[18],node[19] );
270 else if (nbnode == 27) {
271 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
272 node[4], node[5], node[6], node[7],
273 node[8], node[9], node[10],node[11],
274 node[12],node[13],node[14],node[15],
275 node[16],node[17],node[18],node[19],
276 node[20],node[21],node[22],node[23],
277 node[24],node[25],node[26], ID);
278 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
279 node[4], node[5], node[6], node[7],
280 node[8], node[9], node[10],node[11],
281 node[12],node[13],node[14],node[15],
282 node[16],node[17],node[18],node[19],
283 node[20],node[21],node[22],node[23],
284 node[24],node[25],node[26] );
291 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
292 else e = mesh->AddEdge (node[0], node[1] );
294 else if ( nbnode == 3 ) {
295 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
296 else e = mesh->AddEdge (node[0], node[1], node[2] );
300 case SMDSAbs_0DElement:
302 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
303 else e = mesh->Add0DElement (node[0] );
308 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
309 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
313 if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
314 else e = mesh->AddBall (node[0], ballDiameter);
319 if ( e ) myLastCreatedElems.Append( e );
323 //=======================================================================
327 //=======================================================================
329 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
330 const SMDSAbs_ElementType type,
334 vector<const SMDS_MeshNode*> nodes;
335 nodes.reserve( nodeIDs.size() );
336 vector<int>::const_iterator id = nodeIDs.begin();
337 while ( id != nodeIDs.end() ) {
338 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
339 nodes.push_back( node );
343 return AddElement( nodes, type, isPoly, ID );
346 //=======================================================================
348 //purpose : Remove a node or an element.
349 // Modify a compute state of sub-meshes which become empty
350 //=======================================================================
352 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
355 myLastCreatedElems.Clear();
356 myLastCreatedNodes.Clear();
358 SMESHDS_Mesh* aMesh = GetMeshDS();
359 set< SMESH_subMesh *> smmap;
362 list<int>::const_iterator it = theIDs.begin();
363 for ( ; it != theIDs.end(); it++ ) {
364 const SMDS_MeshElement * elem;
366 elem = aMesh->FindNode( *it );
368 elem = aMesh->FindElement( *it );
372 // Notify VERTEX sub-meshes about modification
374 const SMDS_MeshNode* node = cast2Node( elem );
375 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
376 if ( int aShapeID = node->getshapeId() )
377 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
380 // Find sub-meshes to notify about modification
381 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
382 // while ( nodeIt->more() ) {
383 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
384 // const SMDS_PositionPtr& aPosition = node->GetPosition();
385 // if ( aPosition.get() ) {
386 // if ( int aShapeID = aPosition->GetShapeId() ) {
387 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
388 // smmap.insert( sm );
395 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
397 aMesh->RemoveElement( elem );
401 // Notify sub-meshes about modification
402 if ( !smmap.empty() ) {
403 set< SMESH_subMesh *>::iterator smIt;
404 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
405 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
408 // // Check if the whole mesh becomes empty
409 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
410 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
415 //================================================================================
417 * \brief Create 0D elements on all nodes of the given object except those
418 * nodes on which a 0D element already exists.
419 * \param elements - Elements on whose nodes to create 0D elements; if empty,
420 * the all mesh is treated
421 * \param all0DElems - returns all 0D elements found or created on nodes of \a elements
423 //================================================================================
425 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
426 TIDSortedElemSet& all0DElems )
428 SMDS_ElemIteratorPtr elemIt;
429 vector< const SMDS_MeshElement* > allNodes;
430 if ( elements.empty() )
432 allNodes.reserve( GetMeshDS()->NbNodes() );
433 elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
434 while ( elemIt->more() )
435 allNodes.push_back( elemIt->next() );
437 elemIt = elemSetIterator( allNodes );
441 elemIt = elemSetIterator( elements );
444 while ( elemIt->more() )
446 const SMDS_MeshElement* e = elemIt->next();
447 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
448 while ( nodeIt->more() )
450 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
451 SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
453 all0DElems.insert( it0D->next() );
455 myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
456 all0DElems.insert( myLastCreatedElems.Last() );
462 //=======================================================================
463 //function : FindShape
464 //purpose : Return an index of the shape theElem is on
465 // or zero if a shape not found
466 //=======================================================================
468 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
470 myLastCreatedElems.Clear();
471 myLastCreatedNodes.Clear();
473 SMESHDS_Mesh * aMesh = GetMeshDS();
474 if ( aMesh->ShapeToMesh().IsNull() )
477 int aShapeID = theElem->getshapeId();
481 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
482 if ( sm->Contains( theElem ))
485 if ( theElem->GetType() == SMDSAbs_Node ) {
486 MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
489 MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
492 TopoDS_Shape aShape; // the shape a node of theElem is on
493 if ( theElem->GetType() != SMDSAbs_Node )
495 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
496 while ( nodeIt->more() ) {
497 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
498 if ((aShapeID = node->getshapeId()) > 0) {
499 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
500 if ( sm->Contains( theElem ))
502 if ( aShape.IsNull() )
503 aShape = aMesh->IndexToShape( aShapeID );
509 // None of nodes is on a proper shape,
510 // find the shape among ancestors of aShape on which a node is
511 if ( !aShape.IsNull() ) {
512 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
513 for ( ; ancIt.More(); ancIt.Next() ) {
514 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
515 if ( sm && sm->Contains( theElem ))
516 return aMesh->ShapeToIndex( ancIt.Value() );
521 const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
522 map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
523 for ( ; id_sm != id2sm.end(); ++id_sm )
524 if ( id_sm->second->Contains( theElem ))
528 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
532 //=======================================================================
533 //function : IsMedium
535 //=======================================================================
537 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
538 const SMDSAbs_ElementType typeToCheck)
540 bool isMedium = false;
541 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
542 while (it->more() && !isMedium ) {
543 const SMDS_MeshElement* elem = it->next();
544 isMedium = elem->IsMediumNode(node);
549 //=======================================================================
550 //function : shiftNodesQuadTria
551 //purpose : Shift nodes in the array corresponded to quadratic triangle
552 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
553 //=======================================================================
555 static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
557 const SMDS_MeshNode* nd1 = aNodes[0];
558 aNodes[0] = aNodes[1];
559 aNodes[1] = aNodes[2];
561 const SMDS_MeshNode* nd2 = aNodes[3];
562 aNodes[3] = aNodes[4];
563 aNodes[4] = aNodes[5];
567 //=======================================================================
568 //function : nbEdgeConnectivity
569 //purpose : return number of the edges connected with the theNode.
570 // if theEdges has connections with the other type of the
571 // elements, return -1
572 //=======================================================================
574 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
576 // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
578 // while(elemIt->more()) {
583 return theNode->NbInverseElements();
586 //=======================================================================
587 //function : getNodesFromTwoTria
589 //=======================================================================
591 static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
592 const SMDS_MeshElement * theTria2,
593 vector< const SMDS_MeshNode*>& N1,
594 vector< const SMDS_MeshNode*>& N2)
596 N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
597 if ( N1.size() < 6 ) return false;
598 N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
599 if ( N2.size() < 6 ) return false;
601 int sames[3] = {-1,-1,-1};
613 if(nbsames!=2) return false;
615 shiftNodesQuadTria(N1);
617 shiftNodesQuadTria(N1);
620 i = sames[0] + sames[1] + sames[2];
622 shiftNodesQuadTria(N2);
624 // now we receive following N1 and N2 (using numeration as in the image below)
625 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
626 // i.e. first nodes from both arrays form a new diagonal
630 //=======================================================================
631 //function : InverseDiag
632 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
633 // but having other common link.
634 // Return False if args are improper
635 //=======================================================================
637 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
638 const SMDS_MeshElement * theTria2 )
640 MESSAGE("InverseDiag");
641 myLastCreatedElems.Clear();
642 myLastCreatedNodes.Clear();
644 if (!theTria1 || !theTria2)
647 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
648 if (!F1) return false;
649 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
650 if (!F2) return false;
651 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
652 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
654 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
655 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
659 // put nodes in array and find out indices of the same ones
660 const SMDS_MeshNode* aNodes [6];
661 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
663 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
664 while ( it->more() ) {
665 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
667 if ( i > 2 ) // theTria2
668 // find same node of theTria1
669 for ( int j = 0; j < 3; j++ )
670 if ( aNodes[ i ] == aNodes[ j ]) {
679 return false; // theTria1 is not a triangle
680 it = theTria2->nodesIterator();
682 if ( i == 6 && it->more() )
683 return false; // theTria2 is not a triangle
686 // find indices of 1,2 and of A,B in theTria1
687 int iA = 0, iB = 0, i1 = 0, i2 = 0;
688 for ( i = 0; i < 6; i++ ) {
689 if ( sameInd [ i ] == 0 ) {
698 // nodes 1 and 2 should not be the same
699 if ( aNodes[ i1 ] == aNodes[ i2 ] )
703 aNodes[ iA ] = aNodes[ i2 ];
705 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
707 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
708 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
712 } // end if(F1 && F2)
714 // check case of quadratic faces
715 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
716 theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
718 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
719 theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
723 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
724 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
732 vector< const SMDS_MeshNode* > N1;
733 vector< const SMDS_MeshNode* > N2;
734 if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
736 // now we receive following N1 and N2 (using numeration as above image)
737 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
738 // i.e. first nodes from both arrays determ new diagonal
740 vector< const SMDS_MeshNode*> N1new( N1.size() );
741 vector< const SMDS_MeshNode*> N2new( N2.size() );
742 N1new.back() = N1.back(); // central node of biquadratic
743 N2new.back() = N2.back();
744 N1new[0] = N1[0]; N2new[0] = N1[0];
745 N1new[1] = N2[0]; N2new[1] = N1[1];
746 N1new[2] = N2[1]; N2new[2] = N2[0];
747 N1new[3] = N1[4]; N2new[3] = N1[3];
748 N1new[4] = N2[3]; N2new[4] = N2[5];
749 N1new[5] = N1[5]; N2new[5] = N1[4];
750 // change nodes in faces
751 GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
752 GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
754 // move the central node of biquadratic triangle
755 SMESH_MesherHelper helper( *GetMesh() );
756 for ( int is2nd = 0; is2nd < 2; ++is2nd )
758 const SMDS_MeshElement* tria = is2nd ? theTria2 : theTria1;
759 vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
760 if ( nodes.size() < 7 )
762 helper.SetSubShape( tria->getshapeId() );
763 const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
767 xyz = ( SMESH_TNodeXYZ( nodes[3] ) +
768 SMESH_TNodeXYZ( nodes[4] ) +
769 SMESH_TNodeXYZ( nodes[5] )) / 3.;
774 gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
775 helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
776 helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
778 Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
779 xyz = S->Value( uv.X(), uv.Y() );
780 xyz.Transform( loc );
781 if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE && // set UV
782 nodes[6]->getshapeId() > 0 )
783 GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
785 GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
790 //=======================================================================
791 //function : findTriangles
792 //purpose : find triangles sharing theNode1-theNode2 link
793 //=======================================================================
795 static bool findTriangles(const SMDS_MeshNode * theNode1,
796 const SMDS_MeshNode * theNode2,
797 const SMDS_MeshElement*& theTria1,
798 const SMDS_MeshElement*& theTria2)
800 if ( !theNode1 || !theNode2 ) return false;
802 theTria1 = theTria2 = 0;
804 set< const SMDS_MeshElement* > emap;
805 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
807 const SMDS_MeshElement* elem = it->next();
808 if ( elem->NbCornerNodes() == 3 )
811 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
813 const SMDS_MeshElement* elem = it->next();
814 if ( emap.count( elem )) {
822 // theTria1 must be element with minimum ID
823 if ( theTria2->GetID() < theTria1->GetID() )
824 std::swap( theTria2, theTria1 );
832 //=======================================================================
833 //function : InverseDiag
834 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
835 // with ones built on the same 4 nodes but having other common link.
836 // Return false if proper faces not found
837 //=======================================================================
839 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
840 const SMDS_MeshNode * theNode2)
842 myLastCreatedElems.Clear();
843 myLastCreatedNodes.Clear();
845 MESSAGE( "::InverseDiag()" );
847 const SMDS_MeshElement *tr1, *tr2;
848 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
851 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
852 if (!F1) return false;
853 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
854 if (!F2) return false;
855 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
856 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
858 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
859 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
863 // put nodes in array
864 // and find indices of 1,2 and of A in tr1 and of B in tr2
865 int i, iA1 = 0, i1 = 0;
866 const SMDS_MeshNode* aNodes1 [3];
867 SMDS_ElemIteratorPtr it;
868 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
869 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
870 if ( aNodes1[ i ] == theNode1 )
871 iA1 = i; // node A in tr1
872 else if ( aNodes1[ i ] != theNode2 )
876 const SMDS_MeshNode* aNodes2 [3];
877 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
878 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
879 if ( aNodes2[ i ] == theNode2 )
880 iB2 = i; // node B in tr2
881 else if ( aNodes2[ i ] != theNode1 )
885 // nodes 1 and 2 should not be the same
886 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
890 aNodes1[ iA1 ] = aNodes2[ i2 ];
892 aNodes2[ iB2 ] = aNodes1[ i1 ];
894 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
895 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
900 // check case of quadratic faces
901 return InverseDiag(tr1,tr2);
904 //=======================================================================
905 //function : getQuadrangleNodes
906 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
907 // fusion of triangles tr1 and tr2 having shared link on
908 // theNode1 and theNode2
909 //=======================================================================
911 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
912 const SMDS_MeshNode * theNode1,
913 const SMDS_MeshNode * theNode2,
914 const SMDS_MeshElement * tr1,
915 const SMDS_MeshElement * tr2 )
917 if( tr1->NbNodes() != tr2->NbNodes() )
919 // find the 4-th node to insert into tr1
920 const SMDS_MeshNode* n4 = 0;
921 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
923 while ( !n4 && i<3 ) {
924 const SMDS_MeshNode * n = cast2Node( it->next() );
926 bool isDiag = ( n == theNode1 || n == theNode2 );
930 // Make an array of nodes to be in a quadrangle
931 int iNode = 0, iFirstDiag = -1;
932 it = tr1->nodesIterator();
935 const SMDS_MeshNode * n = cast2Node( it->next() );
937 bool isDiag = ( n == theNode1 || n == theNode2 );
939 if ( iFirstDiag < 0 )
941 else if ( iNode - iFirstDiag == 1 )
942 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
944 else if ( n == n4 ) {
945 return false; // tr1 and tr2 should not have all the same nodes
947 theQuadNodes[ iNode++ ] = n;
949 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
950 theQuadNodes[ iNode ] = n4;
955 //=======================================================================
956 //function : DeleteDiag
957 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
958 // with a quadrangle built on the same 4 nodes.
959 // Return false if proper faces not found
960 //=======================================================================
962 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
963 const SMDS_MeshNode * theNode2)
965 myLastCreatedElems.Clear();
966 myLastCreatedNodes.Clear();
968 MESSAGE( "::DeleteDiag()" );
970 const SMDS_MeshElement *tr1, *tr2;
971 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
974 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
975 if (!F1) return false;
976 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
977 if (!F2) return false;
978 SMESHDS_Mesh * aMesh = GetMeshDS();
980 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
981 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
983 const SMDS_MeshNode* aNodes [ 4 ];
984 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
987 const SMDS_MeshElement* newElem = 0;
988 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
989 myLastCreatedElems.Append(newElem);
990 AddToSameGroups( newElem, tr1, aMesh );
991 int aShapeId = tr1->getshapeId();
994 aMesh->SetMeshElementOnShape( newElem, aShapeId );
996 aMesh->RemoveElement( tr1 );
997 aMesh->RemoveElement( tr2 );
1002 // check case of quadratic faces
1003 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
1005 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
1009 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
1010 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
1018 vector< const SMDS_MeshNode* > N1;
1019 vector< const SMDS_MeshNode* > N2;
1020 if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
1022 // now we receive following N1 and N2 (using numeration as above image)
1023 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1024 // i.e. first nodes from both arrays determ new diagonal
1026 const SMDS_MeshNode* aNodes[8];
1036 const SMDS_MeshElement* newElem = 0;
1037 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1038 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1039 myLastCreatedElems.Append(newElem);
1040 AddToSameGroups( newElem, tr1, aMesh );
1041 int aShapeId = tr1->getshapeId();
1044 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1046 aMesh->RemoveElement( tr1 );
1047 aMesh->RemoveElement( tr2 );
1049 // remove middle node (9)
1050 GetMeshDS()->RemoveNode( N1[4] );
1055 //=======================================================================
1056 //function : Reorient
1057 //purpose : Reverse theElement orientation
1058 //=======================================================================
1060 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1062 MESSAGE("Reorient");
1063 myLastCreatedElems.Clear();
1064 myLastCreatedNodes.Clear();
1068 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1069 if ( !it || !it->more() )
1072 const SMDSAbs_ElementType type = theElem->GetType();
1073 if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
1076 const SMDSAbs_EntityType geomType = theElem->GetEntityType();
1077 if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
1079 const SMDS_VtkVolume* aPolyedre =
1080 dynamic_cast<const SMDS_VtkVolume*>( theElem );
1082 MESSAGE("Warning: bad volumic element");
1085 const int nbFaces = aPolyedre->NbFaces();
1086 vector<const SMDS_MeshNode *> poly_nodes;
1087 vector<int> quantities (nbFaces);
1089 // reverse each face of the polyedre
1090 for (int iface = 1; iface <= nbFaces; iface++) {
1091 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1092 quantities[iface - 1] = nbFaceNodes;
1094 for (inode = nbFaceNodes; inode >= 1; inode--) {
1095 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1096 poly_nodes.push_back(curNode);
1099 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1101 else // other elements
1103 vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
1104 const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType );
1105 if ( interlace.empty() )
1107 std::reverse( nodes.begin(), nodes.end() ); // polygon
1109 else if ( interlace.size() > 1 )
1111 SMDS_MeshCell::applyInterlace( interlace, nodes );
1113 return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
1118 //================================================================================
1120 * \brief Reorient faces.
1121 * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1122 * \param theDirection - desired direction of normal of \a theFace
1123 * \param theFace - one of \a theFaces that sould be oriented according to
1124 * \a theDirection and whose orientation defines orientation of other faces
1125 * \return number of reoriented faces.
1127 //================================================================================
1129 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces,
1130 const gp_Dir& theDirection,
1131 const SMDS_MeshElement * theFace)
1134 if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1136 if ( theFaces.empty() )
1138 SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1139 while ( fIt->more() )
1140 theFaces.insert( theFaces.end(), fIt->next() );
1143 // orient theFace according to theDirection
1145 SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
1146 if ( normal * theDirection.XYZ() < 0 )
1147 nbReori += Reorient( theFace );
1149 // Orient other faces
1151 set< const SMDS_MeshElement* > startFaces, visitedFaces;
1152 TIDSortedElemSet avoidSet;
1153 set< SMESH_TLink > checkedLinks;
1154 pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1156 if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1157 theFaces.erase( theFace );
1158 startFaces.insert( theFace );
1160 int nodeInd1, nodeInd2;
1161 const SMDS_MeshElement* otherFace;
1162 vector< const SMDS_MeshElement* > facesNearLink;
1163 vector< std::pair< int, int > > nodeIndsOfFace;
1165 set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1166 while ( !startFaces.empty() )
1168 startFace = startFaces.begin();
1169 theFace = *startFace;
1170 startFaces.erase( startFace );
1171 if ( !visitedFaces.insert( theFace ).second )
1175 avoidSet.insert(theFace);
1177 NLink link( theFace->GetNode( 0 ), 0 );
1179 const int nbNodes = theFace->NbCornerNodes();
1180 for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1182 link.second = theFace->GetNode(( i+1 ) % nbNodes );
1183 linkIt_isNew = checkedLinks.insert( link );
1184 if ( !linkIt_isNew.second )
1186 // link has already been checked and won't be encountered more
1187 // if the group (theFaces) is manifold
1188 //checkedLinks.erase( linkIt_isNew.first );
1192 facesNearLink.clear();
1193 nodeIndsOfFace.clear();
1194 while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
1196 &nodeInd1, &nodeInd2 )))
1197 if ( otherFace != theFace)
1199 facesNearLink.push_back( otherFace );
1200 nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1201 avoidSet.insert( otherFace );
1203 if ( facesNearLink.size() > 1 )
1205 // NON-MANIFOLD mesh shell !
1206 // select a face most co-directed with theFace,
1207 // other faces won't be visited this time
1209 SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
1210 double proj, maxProj = -1;
1211 for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1212 SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1213 if (( proj = Abs( NF * NOF )) > maxProj ) {
1215 otherFace = facesNearLink[i];
1216 nodeInd1 = nodeIndsOfFace[i].first;
1217 nodeInd2 = nodeIndsOfFace[i].second;
1220 // not to visit rejected faces
1221 for ( size_t i = 0; i < facesNearLink.size(); ++i )
1222 if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1223 visitedFaces.insert( facesNearLink[i] );
1225 else if ( facesNearLink.size() == 1 )
1227 otherFace = facesNearLink[0];
1228 nodeInd1 = nodeIndsOfFace.back().first;
1229 nodeInd2 = nodeIndsOfFace.back().second;
1231 if ( otherFace && otherFace != theFace)
1233 // link must be reverse in otherFace if orientation ot otherFace
1234 // is same as that of theFace
1235 if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1237 nbReori += Reorient( otherFace );
1239 startFaces.insert( otherFace );
1242 std::swap( link.first, link.second ); // reverse the link
1248 //=======================================================================
1249 //function : getBadRate
1251 //=======================================================================
1253 static double getBadRate (const SMDS_MeshElement* theElem,
1254 SMESH::Controls::NumericalFunctorPtr& theCrit)
1256 SMESH::Controls::TSequenceOfXYZ P;
1257 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1259 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1260 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1263 //=======================================================================
1264 //function : QuadToTri
1265 //purpose : Cut quadrangles into triangles.
1266 // theCrit is used to select a diagonal to cut
1267 //=======================================================================
1269 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1270 SMESH::Controls::NumericalFunctorPtr theCrit)
1272 myLastCreatedElems.Clear();
1273 myLastCreatedNodes.Clear();
1275 if ( !theCrit.get() )
1278 SMESHDS_Mesh * aMesh = GetMeshDS();
1280 Handle(Geom_Surface) surface;
1281 SMESH_MesherHelper helper( *GetMesh() );
1283 TIDSortedElemSet::iterator itElem;
1284 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
1286 const SMDS_MeshElement* elem = *itElem;
1287 if ( !elem || elem->GetType() != SMDSAbs_Face )
1289 if ( elem->NbCornerNodes() != 4 )
1292 // retrieve element nodes
1293 vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1295 // compare two sets of possible triangles
1296 double aBadRate1, aBadRate2; // to what extent a set is bad
1297 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1298 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1299 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1301 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1302 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1303 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1305 const int aShapeId = FindShape( elem );
1306 const SMDS_MeshElement* newElem1 = 0;
1307 const SMDS_MeshElement* newElem2 = 0;
1309 if ( !elem->IsQuadratic() ) // split liner quadrangle
1311 // for MaxElementLength2D functor we return minimum diagonal for splitting,
1312 // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1313 if ( aBadRate1 <= aBadRate2 ) {
1314 // tr1 + tr2 is better
1315 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1316 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1319 // tr3 + tr4 is better
1320 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1321 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1324 else // split quadratic quadrangle
1326 helper.SetIsQuadratic( true );
1327 helper.SetIsBiQuadratic( aNodes.size() == 9 );
1329 helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
1330 if ( aNodes.size() == 9 )
1332 helper.SetIsBiQuadratic( true );
1333 if ( aBadRate1 <= aBadRate2 )
1334 helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
1336 helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
1338 // create a new element
1339 if ( aBadRate1 <= aBadRate2 ) {
1340 newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
1341 newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
1344 newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
1345 newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
1349 // care of a new element
1351 myLastCreatedElems.Append(newElem1);
1352 myLastCreatedElems.Append(newElem2);
1353 AddToSameGroups( newElem1, elem, aMesh );
1354 AddToSameGroups( newElem2, elem, aMesh );
1356 // put a new triangle on the same shape
1358 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1359 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1361 aMesh->RemoveElement( elem );
1366 //=======================================================================
1368 * \brief Split each of given quadrangles into 4 triangles.
1369 * \param theElems - The faces to be splitted. If empty all faces are split.
1371 //=======================================================================
1373 void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
1375 myLastCreatedElems.Clear();
1376 myLastCreatedNodes.Clear();
1378 SMESH_MesherHelper helper( *GetMesh() );
1379 helper.SetElementsOnShape( true );
1381 SMDS_ElemIteratorPtr faceIt;
1382 if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
1383 else faceIt = elemSetIterator( theElems );
1386 gp_XY uv [9]; uv[8] = gp_XY(0,0);
1388 vector< const SMDS_MeshNode* > nodes;
1389 SMESHDS_SubMesh* subMeshDS;
1391 Handle(Geom_Surface) surface;
1392 TopLoc_Location loc;
1394 while ( faceIt->more() )
1396 const SMDS_MeshElement* quad = faceIt->next();
1397 if ( !quad || quad->NbCornerNodes() != 4 )
1400 // get a surface the quad is on
1402 if ( quad->getshapeId() < 1 )
1405 helper.SetSubShape( 0 );
1408 else if ( quad->getshapeId() != helper.GetSubShapeID() )
1410 helper.SetSubShape( quad->getshapeId() );
1411 if ( !helper.GetSubShape().IsNull() &&
1412 helper.GetSubShape().ShapeType() == TopAbs_FACE )
1414 F = TopoDS::Face( helper.GetSubShape() );
1415 surface = BRep_Tool::Surface( F, loc );
1416 subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
1420 helper.SetSubShape( 0 );
1425 // create a central node
1427 const SMDS_MeshNode* nCentral;
1428 nodes.assign( quad->begin_nodes(), quad->end_nodes() );
1430 if ( nodes.size() == 9 )
1432 nCentral = nodes.back();
1439 for ( ; iN < nodes.size(); ++iN )
1440 xyz[ iN ] = SMESH_TNodeXYZ( nodes[ iN ] );
1442 for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
1443 xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
1445 xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
1446 xyz[0], xyz[1], xyz[2], xyz[3],
1447 xyz[4], xyz[5], xyz[6], xyz[7] );
1451 for ( ; iN < nodes.size(); ++iN )
1452 uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
1454 for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
1455 uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
1457 uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
1458 uv[0], uv[1], uv[2], uv[3],
1459 uv[4], uv[5], uv[6], uv[7] );
1461 gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
1465 nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
1466 uv[8].X(), uv[8].Y() );
1467 myLastCreatedNodes.Append( nCentral );
1470 // create 4 triangles
1472 GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
1474 helper.SetIsQuadratic ( nodes.size() > 4 );
1475 helper.SetIsBiQuadratic( nodes.size() == 9 );
1476 if ( helper.GetIsQuadratic() )
1477 helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
1479 for ( int i = 0; i < 4; ++i )
1481 SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
1484 ReplaceElemInGroups( tria, quad, GetMeshDS() );
1485 myLastCreatedElems.Append( tria );
1490 //=======================================================================
1491 //function : BestSplit
1492 //purpose : Find better diagonal for cutting.
1493 //=======================================================================
1495 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1496 SMESH::Controls::NumericalFunctorPtr theCrit)
1498 myLastCreatedElems.Clear();
1499 myLastCreatedNodes.Clear();
1504 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1507 if( theQuad->NbNodes()==4 ||
1508 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1510 // retrieve element nodes
1511 const SMDS_MeshNode* aNodes [4];
1512 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1514 //while (itN->more())
1516 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1518 // compare two sets of possible triangles
1519 double aBadRate1, aBadRate2; // to what extent a set is bad
1520 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1521 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1522 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1524 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1525 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1526 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1527 // for MaxElementLength2D functor we return minimum diagonal for splitting,
1528 // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1529 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1530 return 1; // diagonal 1-3
1532 return 2; // diagonal 2-4
1539 // Methods of splitting volumes into tetra
1541 const int theHexTo5_1[5*4+1] =
1543 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1545 const int theHexTo5_2[5*4+1] =
1547 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1549 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1551 const int theHexTo6_1[6*4+1] =
1553 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
1555 const int theHexTo6_2[6*4+1] =
1557 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
1559 const int theHexTo6_3[6*4+1] =
1561 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
1563 const int theHexTo6_4[6*4+1] =
1565 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
1567 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1569 const int thePyraTo2_1[2*4+1] =
1571 0, 1, 2, 4, 0, 2, 3, 4, -1
1573 const int thePyraTo2_2[2*4+1] =
1575 1, 2, 3, 4, 1, 3, 0, 4, -1
1577 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1579 const int thePentaTo3_1[3*4+1] =
1581 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1583 const int thePentaTo3_2[3*4+1] =
1585 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1587 const int thePentaTo3_3[3*4+1] =
1589 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1591 const int thePentaTo3_4[3*4+1] =
1593 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1595 const int thePentaTo3_5[3*4+1] =
1597 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1599 const int thePentaTo3_6[3*4+1] =
1601 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1603 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1604 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1606 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1609 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1610 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1611 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1616 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1617 bool _baryNode; //!< additional node is to be created at cell barycenter
1618 bool _ownConn; //!< to delete _connectivity in destructor
1619 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1621 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1622 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1623 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1624 bool hasFacet( const TTriangleFacet& facet ) const
1626 const int* tetConn = _connectivity;
1627 for ( ; tetConn[0] >= 0; tetConn += 4 )
1628 if (( facet.contains( tetConn[0] ) +
1629 facet.contains( tetConn[1] ) +
1630 facet.contains( tetConn[2] ) +
1631 facet.contains( tetConn[3] )) == 3 )
1637 //=======================================================================
1639 * \brief return TSplitMethod for the given element
1641 //=======================================================================
1643 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1645 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1647 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1648 // an edge and a face barycenter; tertaherdons are based on triangles and
1649 // a volume barycenter
1650 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1652 // Find out how adjacent volumes are split
1654 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1655 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1656 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1658 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1659 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1660 if ( nbNodes < 4 ) continue;
1662 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1663 const int* nInd = vol.GetFaceNodesIndices( iF );
1666 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1667 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1668 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1669 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1673 int iCom = 0; // common node of triangle faces to split into
1674 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1676 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1677 nInd[ iQ * ( (iCom+1)%nbNodes )],
1678 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1679 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1680 nInd[ iQ * ( (iCom+2)%nbNodes )],
1681 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1682 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1684 triaSplits.push_back( t012 );
1685 triaSplits.push_back( t023 );
1690 if ( !triaSplits.empty() )
1691 hasAdjacentSplits = true;
1694 // Among variants of split method select one compliant with adjacent volumes
1696 TSplitMethod method;
1697 if ( !vol.Element()->IsPoly() && !is24TetMode )
1699 int nbVariants = 2, nbTet = 0;
1700 const int** connVariants = 0;
1701 switch ( vol.Element()->GetEntityType() )
1703 case SMDSEntity_Hexa:
1704 case SMDSEntity_Quad_Hexa:
1705 case SMDSEntity_TriQuad_Hexa:
1706 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1707 connVariants = theHexTo5, nbTet = 5;
1709 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1711 case SMDSEntity_Pyramid:
1712 case SMDSEntity_Quad_Pyramid:
1713 connVariants = thePyraTo2; nbTet = 2;
1715 case SMDSEntity_Penta:
1716 case SMDSEntity_Quad_Penta:
1717 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1722 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1724 // check method compliancy with adjacent tetras,
1725 // all found splits must be among facets of tetras described by this method
1726 method = TSplitMethod( nbTet, connVariants[variant] );
1727 if ( hasAdjacentSplits && method._nbTetra > 0 )
1729 bool facetCreated = true;
1730 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1732 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1733 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1734 facetCreated = method.hasFacet( *facet );
1736 if ( !facetCreated )
1737 method = TSplitMethod(0); // incompatible method
1741 if ( method._nbTetra < 1 )
1743 // No standard method is applicable, use a generic solution:
1744 // each facet of a volume is split into triangles and
1745 // each of triangles and a volume barycenter form a tetrahedron.
1747 const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1749 int* connectivity = new int[ maxTetConnSize + 1 ];
1750 method._connectivity = connectivity;
1751 method._ownConn = true;
1752 method._baryNode = !isHex27; // to create central node or not
1755 int baryCenInd = vol.NbNodes() - int( isHex27 );
1756 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1758 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1759 const int* nInd = vol.GetFaceNodesIndices( iF );
1760 // find common node of triangle facets of tetra to create
1761 int iCommon = 0; // index in linear numeration
1762 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1763 if ( !triaSplits.empty() )
1766 const TTriangleFacet* facet = &triaSplits.front();
1767 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1768 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1769 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1772 else if ( nbNodes > 3 && !is24TetMode )
1774 // find the best method of splitting into triangles by aspect ratio
1775 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1776 map< double, int > badness2iCommon;
1777 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1778 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1779 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1782 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1784 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1785 nodes[ iQ*((iLast-1)%nbNodes)],
1786 nodes[ iQ*((iLast )%nbNodes)]);
1787 badness += getBadRate( &tria, aspectRatio );
1789 badness2iCommon.insert( make_pair( badness, iCommon ));
1791 // use iCommon with lowest badness
1792 iCommon = badness2iCommon.begin()->second;
1794 if ( iCommon >= nbNodes )
1795 iCommon = 0; // something wrong
1797 // fill connectivity of tetrahedra based on a current face
1798 int nbTet = nbNodes - 2;
1799 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1804 faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1805 method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1809 method._faceBaryNode[ iF ] = 0;
1810 faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1813 for ( int i = 0; i < nbTet; ++i )
1815 int i1 = i, i2 = (i+1) % nbNodes;
1816 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1817 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1818 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1819 connectivity[ connSize++ ] = faceBaryCenInd;
1820 connectivity[ connSize++ ] = baryCenInd;
1825 for ( int i = 0; i < nbTet; ++i )
1827 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1828 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1829 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1830 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1831 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1832 connectivity[ connSize++ ] = baryCenInd;
1835 method._nbTetra += nbTet;
1837 } // loop on volume faces
1839 connectivity[ connSize++ ] = -1;
1841 } // end of generic solution
1845 //================================================================================
1847 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1849 //================================================================================
1851 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1853 // find the tetrahedron including the three nodes of facet
1854 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1855 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1856 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1857 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1858 while ( volIt1->more() )
1860 const SMDS_MeshElement* v = volIt1->next();
1861 SMDSAbs_EntityType type = v->GetEntityType();
1862 if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1864 if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1865 continue; // medium node not allowed
1866 const int ind2 = v->GetNodeIndex( n2 );
1867 if ( ind2 < 0 || 3 < ind2 )
1869 const int ind3 = v->GetNodeIndex( n3 );
1870 if ( ind3 < 0 || 3 < ind3 )
1877 //=======================================================================
1879 * \brief A key of a face of volume
1881 //=======================================================================
1883 struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1885 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1887 TIDSortedNodeSet sortedNodes;
1888 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1889 int nbNodes = vol.NbFaceNodes( iF );
1890 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1891 for ( int i = 0; i < nbNodes; i += iQ )
1892 sortedNodes.insert( fNodes[i] );
1893 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1894 first.first = (*(n++))->GetID();
1895 first.second = (*(n++))->GetID();
1896 second.first = (*(n++))->GetID();
1897 second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1902 //=======================================================================
1903 //function : SplitVolumesIntoTetra
1904 //purpose : Split volume elements into tetrahedra.
1905 //=======================================================================
1907 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1908 const int theMethodFlags)
1910 // std-like iterator on coordinates of nodes of mesh element
1911 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1912 NXyzIterator xyzEnd;
1914 SMDS_VolumeTool volTool;
1915 SMESH_MesherHelper helper( *GetMesh());
1917 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1918 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1920 SMESH_SequenceOfElemPtr newNodes, newElems;
1922 // map face of volume to it's baricenrtic node
1923 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1926 TIDSortedElemSet::const_iterator elem = theElems.begin();
1927 for ( ; elem != theElems.end(); ++elem )
1929 if ( (*elem)->GetType() != SMDSAbs_Volume )
1931 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1932 if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1935 if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1937 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1938 if ( splitMethod._nbTetra < 1 ) continue;
1940 // find submesh to add new tetras to
1941 if ( !subMesh || !subMesh->Contains( *elem ))
1943 int shapeID = FindShape( *elem );
1944 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1945 subMesh = GetMeshDS()->MeshElements( shapeID );
1948 if ( (*elem)->IsQuadratic() )
1951 // add quadratic links to the helper
1952 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1954 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1955 int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1956 for ( int iN = 0; iN < nbN; iN += iQ )
1957 helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1959 helper.SetIsQuadratic( true );
1964 helper.SetIsQuadratic( false );
1966 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1967 helper.SetElementsOnShape( true );
1968 if ( splitMethod._baryNode )
1970 // make a node at barycenter
1971 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1972 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1973 nodes.push_back( gcNode );
1974 newNodes.Append( gcNode );
1976 if ( !splitMethod._faceBaryNode.empty() )
1978 // make or find baricentric nodes of faces
1979 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1980 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1982 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1983 volFace2BaryNode.insert
1984 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1987 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1988 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1990 nodes.push_back( iF_n->second = f_n->second );
1995 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1996 const int* tetConn = splitMethod._connectivity;
1997 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1998 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1999 nodes[ tetConn[1] ],
2000 nodes[ tetConn[2] ],
2001 nodes[ tetConn[3] ]));
2003 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
2005 // Split faces on sides of the split volume
2007 const SMDS_MeshNode** volNodes = volTool.GetNodes();
2008 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2010 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
2011 if ( nbNodes < 4 ) continue;
2013 // find an existing face
2014 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
2015 volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
2016 while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
2017 /*noMedium=*/false))
2020 helper.SetElementsOnShape( false );
2021 vector< const SMDS_MeshElement* > triangles;
2023 // find submesh to add new triangles in
2024 if ( !fSubMesh || !fSubMesh->Contains( face ))
2026 int shapeID = FindShape( face );
2027 fSubMesh = GetMeshDS()->MeshElements( shapeID );
2029 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
2030 if ( iF_n != splitMethod._faceBaryNode.end() )
2032 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
2034 const SMDS_MeshNode* n1 = fNodes[iN];
2035 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
2036 const SMDS_MeshNode *n3 = iF_n->second;
2037 if ( !volTool.IsFaceExternal( iF ))
2039 triangles.push_back( helper.AddFace( n1,n2,n3 ));
2041 if ( fSubMesh && n3->getshapeId() < 1 )
2042 fSubMesh->AddNode( n3 );
2047 // among possible triangles create ones discribed by split method
2048 const int* nInd = volTool.GetFaceNodesIndices( iF );
2049 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
2050 int iCom = 0; // common node of triangle faces to split into
2051 list< TTriangleFacet > facets;
2052 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
2054 TTriangleFacet t012( nInd[ iQ * ( iCom )],
2055 nInd[ iQ * ( (iCom+1)%nbNodes )],
2056 nInd[ iQ * ( (iCom+2)%nbNodes )]);
2057 TTriangleFacet t023( nInd[ iQ * ( iCom )],
2058 nInd[ iQ * ( (iCom+2)%nbNodes )],
2059 nInd[ iQ * ( (iCom+3)%nbNodes )]);
2060 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
2062 facets.push_back( t012 );
2063 facets.push_back( t023 );
2064 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
2065 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
2066 nInd[ iQ * ((iLast-1)%nbNodes )],
2067 nInd[ iQ * ((iLast )%nbNodes )]));
2071 list< TTriangleFacet >::iterator facet = facets.begin();
2072 for ( ; facet != facets.end(); ++facet )
2074 if ( !volTool.IsFaceExternal( iF ))
2075 swap( facet->_n2, facet->_n3 );
2076 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
2077 volNodes[ facet->_n2 ],
2078 volNodes[ facet->_n3 ]));
2081 for ( int i = 0; i < triangles.size(); ++i )
2083 if ( !triangles[i] ) continue;
2085 fSubMesh->AddElement( triangles[i]);
2086 newElems.Append( triangles[i] );
2088 ReplaceElemInGroups( face, triangles, GetMeshDS() );
2089 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2092 } // loop on volume faces to split them into triangles
2094 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
2096 if ( geomType == SMDSEntity_TriQuad_Hexa )
2098 // remove medium nodes that could become free
2099 for ( int i = 20; i < volTool.NbNodes(); ++i )
2100 if ( volNodes[i]->NbInverseElements() == 0 )
2101 GetMeshDS()->RemoveNode( volNodes[i] );
2103 } // loop on volumes to split
2105 myLastCreatedNodes = newNodes;
2106 myLastCreatedElems = newElems;
2109 //=======================================================================
2110 //function : AddToSameGroups
2111 //purpose : add elemToAdd to the groups the elemInGroups belongs to
2112 //=======================================================================
2114 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2115 const SMDS_MeshElement* elemInGroups,
2116 SMESHDS_Mesh * aMesh)
2118 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2119 if (!groups.empty()) {
2120 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2121 for ( ; grIt != groups.end(); grIt++ ) {
2122 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2123 if ( group && group->Contains( elemInGroups ))
2124 group->SMDSGroup().Add( elemToAdd );
2130 //=======================================================================
2131 //function : RemoveElemFromGroups
2132 //purpose : Remove removeelem to the groups the elemInGroups belongs to
2133 //=======================================================================
2134 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2135 SMESHDS_Mesh * aMesh)
2137 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2138 if (!groups.empty())
2140 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2141 for (; GrIt != groups.end(); GrIt++)
2143 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2144 if (!grp || grp->IsEmpty()) continue;
2145 grp->SMDSGroup().Remove(removeelem);
2150 //================================================================================
2152 * \brief Replace elemToRm by elemToAdd in the all groups
2154 //================================================================================
2156 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2157 const SMDS_MeshElement* elemToAdd,
2158 SMESHDS_Mesh * aMesh)
2160 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2161 if (!groups.empty()) {
2162 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2163 for ( ; grIt != groups.end(); grIt++ ) {
2164 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2165 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2166 group->SMDSGroup().Add( elemToAdd );
2171 //================================================================================
2173 * \brief Replace elemToRm by elemToAdd in the all groups
2175 //================================================================================
2177 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2178 const vector<const SMDS_MeshElement*>& elemToAdd,
2179 SMESHDS_Mesh * aMesh)
2181 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2182 if (!groups.empty())
2184 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2185 for ( ; grIt != groups.end(); grIt++ ) {
2186 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2187 if ( group && group->SMDSGroup().Remove( elemToRm ) )
2188 for ( int i = 0; i < elemToAdd.size(); ++i )
2189 group->SMDSGroup().Add( elemToAdd[ i ] );
2194 //=======================================================================
2195 //function : QuadToTri
2196 //purpose : Cut quadrangles into triangles.
2197 // theCrit is used to select a diagonal to cut
2198 //=======================================================================
2200 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2201 const bool the13Diag)
2203 myLastCreatedElems.Clear();
2204 myLastCreatedNodes.Clear();
2206 MESSAGE( "::QuadToTri()" );
2208 SMESHDS_Mesh * aMesh = GetMeshDS();
2210 Handle(Geom_Surface) surface;
2211 SMESH_MesherHelper helper( *GetMesh() );
2213 TIDSortedElemSet::iterator itElem;
2214 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2215 const SMDS_MeshElement* elem = *itElem;
2216 if ( !elem || elem->GetType() != SMDSAbs_Face )
2218 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2219 if(!isquad) continue;
2221 if(elem->NbNodes()==4) {
2222 // retrieve element nodes
2223 const SMDS_MeshNode* aNodes [4];
2224 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2226 while ( itN->more() )
2227 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2229 int aShapeId = FindShape( elem );
2230 const SMDS_MeshElement* newElem1 = 0;
2231 const SMDS_MeshElement* newElem2 = 0;
2233 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2234 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2237 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2238 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2240 myLastCreatedElems.Append(newElem1);
2241 myLastCreatedElems.Append(newElem2);
2242 // put a new triangle on the same shape and add to the same groups
2245 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2246 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2248 AddToSameGroups( newElem1, elem, aMesh );
2249 AddToSameGroups( newElem2, elem, aMesh );
2250 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2251 aMesh->RemoveElement( elem );
2254 // Quadratic quadrangle
2256 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2258 // get surface elem is on
2259 int aShapeId = FindShape( elem );
2260 if ( aShapeId != helper.GetSubShapeID() ) {
2264 shape = aMesh->IndexToShape( aShapeId );
2265 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2266 TopoDS_Face face = TopoDS::Face( shape );
2267 surface = BRep_Tool::Surface( face );
2268 if ( !surface.IsNull() )
2269 helper.SetSubShape( shape );
2273 const SMDS_MeshNode* aNodes [8];
2274 const SMDS_MeshNode* inFaceNode = 0;
2275 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2277 while ( itN->more() ) {
2278 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2279 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2280 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2282 inFaceNode = aNodes[ i-1 ];
2286 // find middle point for (0,1,2,3)
2287 // and create a node in this point;
2289 if ( surface.IsNull() ) {
2291 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2295 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2298 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2300 p = surface->Value( uv.X(), uv.Y() ).XYZ();
2302 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2303 myLastCreatedNodes.Append(newN);
2305 // create a new element
2306 const SMDS_MeshElement* newElem1 = 0;
2307 const SMDS_MeshElement* newElem2 = 0;
2309 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2310 aNodes[6], aNodes[7], newN );
2311 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2312 newN, aNodes[4], aNodes[5] );
2315 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2316 aNodes[7], aNodes[4], newN );
2317 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2318 newN, aNodes[5], aNodes[6] );
2320 myLastCreatedElems.Append(newElem1);
2321 myLastCreatedElems.Append(newElem2);
2322 // put a new triangle on the same shape and add to the same groups
2325 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2326 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2328 AddToSameGroups( newElem1, elem, aMesh );
2329 AddToSameGroups( newElem2, elem, aMesh );
2330 aMesh->RemoveElement( elem );
2337 //=======================================================================
2338 //function : getAngle
2340 //=======================================================================
2342 double getAngle(const SMDS_MeshElement * tr1,
2343 const SMDS_MeshElement * tr2,
2344 const SMDS_MeshNode * n1,
2345 const SMDS_MeshNode * n2)
2347 double angle = 2. * M_PI; // bad angle
2350 SMESH::Controls::TSequenceOfXYZ P1, P2;
2351 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2352 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2355 if(!tr1->IsQuadratic())
2356 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2358 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2359 if ( N1.SquareMagnitude() <= gp::Resolution() )
2361 if(!tr2->IsQuadratic())
2362 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2364 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2365 if ( N2.SquareMagnitude() <= gp::Resolution() )
2368 // find the first diagonal node n1 in the triangles:
2369 // take in account a diagonal link orientation
2370 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2371 for ( int t = 0; t < 2; t++ ) {
2372 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2373 int i = 0, iDiag = -1;
2374 while ( it->more()) {
2375 const SMDS_MeshElement *n = it->next();
2376 if ( n == n1 || n == n2 ) {
2380 if ( i - iDiag == 1 )
2381 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2390 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2393 angle = N1.Angle( N2 );
2398 // =================================================
2399 // class generating a unique ID for a pair of nodes
2400 // and able to return nodes by that ID
2401 // =================================================
2405 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2406 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2409 long GetLinkID (const SMDS_MeshNode * n1,
2410 const SMDS_MeshNode * n2) const
2412 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2415 bool GetNodes (const long theLinkID,
2416 const SMDS_MeshNode* & theNode1,
2417 const SMDS_MeshNode* & theNode2) const
2419 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2420 if ( !theNode1 ) return false;
2421 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2422 if ( !theNode2 ) return false;
2428 const SMESHDS_Mesh* myMesh;
2433 //=======================================================================
2434 //function : TriToQuad
2435 //purpose : Fuse neighbour triangles into quadrangles.
2436 // theCrit is used to select a neighbour to fuse with.
2437 // theMaxAngle is a max angle between element normals at which
2438 // fusion is still performed.
2439 //=======================================================================
2441 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2442 SMESH::Controls::NumericalFunctorPtr theCrit,
2443 const double theMaxAngle)
2445 myLastCreatedElems.Clear();
2446 myLastCreatedNodes.Clear();
2448 MESSAGE( "::TriToQuad()" );
2450 if ( !theCrit.get() )
2453 SMESHDS_Mesh * aMesh = GetMeshDS();
2455 // Prepare data for algo: build
2456 // 1. map of elements with their linkIDs
2457 // 2. map of linkIDs with their elements
2459 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2460 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2461 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2462 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2464 TIDSortedElemSet::iterator itElem;
2465 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
2467 const SMDS_MeshElement* elem = *itElem;
2468 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2469 bool IsTria = ( elem->NbCornerNodes()==3 );
2470 if (!IsTria) continue;
2472 // retrieve element nodes
2473 const SMDS_MeshNode* aNodes [4];
2474 SMDS_NodeIteratorPtr itN = elem->nodeIterator();
2477 aNodes[ i++ ] = itN->next();
2478 aNodes[ 3 ] = aNodes[ 0 ];
2481 for ( i = 0; i < 3; i++ ) {
2482 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2483 // check if elements sharing a link can be fused
2484 itLE = mapLi_listEl.find( link );
2485 if ( itLE != mapLi_listEl.end() ) {
2486 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2488 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2489 //if ( FindShape( elem ) != FindShape( elem2 ))
2490 // continue; // do not fuse triangles laying on different shapes
2491 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2492 continue; // avoid making badly shaped quads
2493 (*itLE).second.push_back( elem );
2496 mapLi_listEl[ link ].push_back( elem );
2498 mapEl_setLi [ elem ].insert( link );
2501 // Clean the maps from the links shared by a sole element, ie
2502 // links to which only one element is bound in mapLi_listEl
2504 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2505 int nbElems = (*itLE).second.size();
2506 if ( nbElems < 2 ) {
2507 const SMDS_MeshElement* elem = (*itLE).second.front();
2508 SMESH_TLink link = (*itLE).first;
2509 mapEl_setLi[ elem ].erase( link );
2510 if ( mapEl_setLi[ elem ].empty() )
2511 mapEl_setLi.erase( elem );
2515 // Algo: fuse triangles into quadrangles
2517 while ( ! mapEl_setLi.empty() ) {
2518 // Look for the start element:
2519 // the element having the least nb of shared links
2520 const SMDS_MeshElement* startElem = 0;
2522 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2523 int nbLinks = (*itEL).second.size();
2524 if ( nbLinks < minNbLinks ) {
2525 startElem = (*itEL).first;
2526 minNbLinks = nbLinks;
2527 if ( minNbLinks == 1 )
2532 // search elements to fuse starting from startElem or links of elements
2533 // fused earlyer - startLinks
2534 list< SMESH_TLink > startLinks;
2535 while ( startElem || !startLinks.empty() ) {
2536 while ( !startElem && !startLinks.empty() ) {
2537 // Get an element to start, by a link
2538 SMESH_TLink linkId = startLinks.front();
2539 startLinks.pop_front();
2540 itLE = mapLi_listEl.find( linkId );
2541 if ( itLE != mapLi_listEl.end() ) {
2542 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2543 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2544 for ( ; itE != listElem.end() ; itE++ )
2545 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2547 mapLi_listEl.erase( itLE );
2552 // Get candidates to be fused
2553 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2554 const SMESH_TLink *link12, *link13;
2556 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2557 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2558 ASSERT( !setLi.empty() );
2559 set< SMESH_TLink >::iterator itLi;
2560 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2562 const SMESH_TLink & link = (*itLi);
2563 itLE = mapLi_listEl.find( link );
2564 if ( itLE == mapLi_listEl.end() )
2567 const SMDS_MeshElement* elem = (*itLE).second.front();
2569 elem = (*itLE).second.back();
2570 mapLi_listEl.erase( itLE );
2571 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2582 // add other links of elem to list of links to re-start from
2583 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2584 set< SMESH_TLink >::iterator it;
2585 for ( it = links.begin(); it != links.end(); it++ ) {
2586 const SMESH_TLink& link2 = (*it);
2587 if ( link2 != link )
2588 startLinks.push_back( link2 );
2592 // Get nodes of possible quadrangles
2593 const SMDS_MeshNode *n12 [4], *n13 [4];
2594 bool Ok12 = false, Ok13 = false;
2595 const SMDS_MeshNode *linkNode1, *linkNode2;
2597 linkNode1 = link12->first;
2598 linkNode2 = link12->second;
2599 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2603 linkNode1 = link13->first;
2604 linkNode2 = link13->second;
2605 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2609 // Choose a pair to fuse
2610 if ( Ok12 && Ok13 ) {
2611 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2612 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2613 double aBadRate12 = getBadRate( &quad12, theCrit );
2614 double aBadRate13 = getBadRate( &quad13, theCrit );
2615 if ( aBadRate13 < aBadRate12 )
2622 // and remove fused elems and remove links from the maps
2623 mapEl_setLi.erase( tr1 );
2626 mapEl_setLi.erase( tr2 );
2627 mapLi_listEl.erase( *link12 );
2628 if ( tr1->NbNodes() == 3 )
2630 const SMDS_MeshElement* newElem = 0;
2631 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2632 myLastCreatedElems.Append(newElem);
2633 AddToSameGroups( newElem, tr1, aMesh );
2634 int aShapeId = tr1->getshapeId();
2636 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2637 aMesh->RemoveElement( tr1 );
2638 aMesh->RemoveElement( tr2 );
2641 vector< const SMDS_MeshNode* > N1;
2642 vector< const SMDS_MeshNode* > N2;
2643 getNodesFromTwoTria(tr1,tr2,N1,N2);
2644 // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
2645 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2646 // i.e. first nodes from both arrays form a new diagonal
2647 const SMDS_MeshNode* aNodes[8];
2656 const SMDS_MeshElement* newElem = 0;
2657 if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2658 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2659 aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2661 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2662 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2663 myLastCreatedElems.Append(newElem);
2664 AddToSameGroups( newElem, tr1, aMesh );
2665 int aShapeId = tr1->getshapeId();
2667 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2668 aMesh->RemoveElement( tr1 );
2669 aMesh->RemoveElement( tr2 );
2670 // remove middle node (9)
2671 if ( N1[4]->NbInverseElements() == 0 )
2672 aMesh->RemoveNode( N1[4] );
2673 if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2674 aMesh->RemoveNode( N1[6] );
2675 if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2676 aMesh->RemoveNode( N2[6] );
2681 mapEl_setLi.erase( tr3 );
2682 mapLi_listEl.erase( *link13 );
2683 if ( tr1->NbNodes() == 3 ) {
2684 const SMDS_MeshElement* newElem = 0;
2685 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2686 myLastCreatedElems.Append(newElem);
2687 AddToSameGroups( newElem, tr1, aMesh );
2688 int aShapeId = tr1->getshapeId();
2690 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2691 aMesh->RemoveElement( tr1 );
2692 aMesh->RemoveElement( tr3 );
2695 vector< const SMDS_MeshNode* > N1;
2696 vector< const SMDS_MeshNode* > N2;
2697 getNodesFromTwoTria(tr1,tr3,N1,N2);
2698 // now we receive following N1 and N2 (using numeration as above image)
2699 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2700 // i.e. first nodes from both arrays form a new diagonal
2701 const SMDS_MeshNode* aNodes[8];
2710 const SMDS_MeshElement* newElem = 0;
2711 if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
2712 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2713 aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
2715 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2716 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2717 myLastCreatedElems.Append(newElem);
2718 AddToSameGroups( newElem, tr1, aMesh );
2719 int aShapeId = tr1->getshapeId();
2721 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2722 aMesh->RemoveElement( tr1 );
2723 aMesh->RemoveElement( tr3 );
2724 // remove middle node (9)
2725 if ( N1[4]->NbInverseElements() == 0 )
2726 aMesh->RemoveNode( N1[4] );
2727 if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
2728 aMesh->RemoveNode( N1[6] );
2729 if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
2730 aMesh->RemoveNode( N2[6] );
2734 // Next element to fuse: the rejected one
2736 startElem = Ok12 ? tr3 : tr2;
2738 } // if ( startElem )
2739 } // while ( startElem || !startLinks.empty() )
2740 } // while ( ! mapEl_setLi.empty() )
2746 /*#define DUMPSO(txt) \
2747 // cout << txt << endl;
2748 //=============================================================================
2752 //=============================================================================
2753 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2757 int tmp = idNodes[ i1 ];
2758 idNodes[ i1 ] = idNodes[ i2 ];
2759 idNodes[ i2 ] = tmp;
2760 gp_Pnt Ptmp = P[ i1 ];
2763 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2766 //=======================================================================
2767 //function : SortQuadNodes
2768 //purpose : Set 4 nodes of a quadrangle face in a good order.
2769 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2771 //=======================================================================
2773 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2778 for ( i = 0; i < 4; i++ ) {
2779 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2781 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2784 gp_Vec V1(P[0], P[1]);
2785 gp_Vec V2(P[0], P[2]);
2786 gp_Vec V3(P[0], P[3]);
2788 gp_Vec Cross1 = V1 ^ V2;
2789 gp_Vec Cross2 = V2 ^ V3;
2792 if (Cross1.Dot(Cross2) < 0)
2797 if (Cross1.Dot(Cross2) < 0)
2801 swap ( i, i + 1, idNodes, P );
2803 // for ( int ii = 0; ii < 4; ii++ ) {
2804 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2805 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2811 //=======================================================================
2812 //function : SortHexaNodes
2813 //purpose : Set 8 nodes of a hexahedron in a good order.
2814 // Return success status
2815 //=======================================================================
2817 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2822 DUMPSO( "INPUT: ========================================");
2823 for ( i = 0; i < 8; i++ ) {
2824 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2825 if ( !n ) return false;
2826 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2827 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2829 DUMPSO( "========================================");
2832 set<int> faceNodes; // ids of bottom face nodes, to be found
2833 set<int> checkedId1; // ids of tried 2-nd nodes
2834 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2835 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2836 int iMin, iLoop1 = 0;
2838 // Loop to try the 2-nd nodes
2840 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2842 // Find not checked 2-nd node
2843 for ( i = 1; i < 8; i++ )
2844 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2845 int id1 = idNodes[i];
2846 swap ( 1, i, idNodes, P );
2847 checkedId1.insert ( id1 );
2851 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2852 // ie that all but meybe one (id3 which is on the same face) nodes
2853 // lay on the same side from the triangle plane.
2855 bool manyInPlane = false; // more than 4 nodes lay in plane
2857 while ( ++iLoop2 < 6 ) {
2859 // get 1-2-3 plane coeffs
2860 Standard_Real A, B, C, D;
2861 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2862 if ( N.SquareMagnitude() > gp::Resolution() )
2864 gp_Pln pln ( P[0], N );
2865 pln.Coefficients( A, B, C, D );
2867 // find the node (iMin) closest to pln
2868 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2870 for ( i = 3; i < 8; i++ ) {
2871 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2872 if ( fabs( dist[i] ) < minDist ) {
2873 minDist = fabs( dist[i] );
2876 if ( fabs( dist[i] ) <= tol )
2877 idInPln.insert( idNodes[i] );
2880 // there should not be more than 4 nodes in bottom plane
2881 if ( idInPln.size() > 1 )
2883 DUMPSO( "### idInPln.size() = " << idInPln.size());
2884 // idInPlane does not contain the first 3 nodes
2885 if ( manyInPlane || idInPln.size() == 5)
2886 return false; // all nodes in one plane
2889 // set the 1-st node to be not in plane
2890 for ( i = 3; i < 8; i++ ) {
2891 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2892 DUMPSO( "### Reset 0-th node");
2893 swap( 0, i, idNodes, P );
2898 // reset to re-check second nodes
2899 leastDist = DBL_MAX;
2903 break; // from iLoop2;
2906 // check that the other 4 nodes are on the same side
2907 bool sameSide = true;
2908 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2909 for ( i = 3; sameSide && i < 8; i++ ) {
2911 sameSide = ( isNeg == dist[i] <= 0.);
2914 // keep best solution
2915 if ( sameSide && minDist < leastDist ) {
2916 leastDist = minDist;
2918 faceNodes.insert( idNodes[ 1 ] );
2919 faceNodes.insert( idNodes[ 2 ] );
2920 faceNodes.insert( idNodes[ iMin ] );
2921 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2922 << " leastDist = " << leastDist);
2923 if ( leastDist <= DBL_MIN )
2928 // set next 3-d node to check
2929 int iNext = 2 + iLoop2;
2931 DUMPSO( "Try 2-nd");
2932 swap ( 2, iNext, idNodes, P );
2934 } // while ( iLoop2 < 6 )
2937 if ( faceNodes.empty() ) return false;
2939 // Put the faceNodes in proper places
2940 for ( i = 4; i < 8; i++ ) {
2941 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2942 // find a place to put
2944 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2946 DUMPSO( "Set faceNodes");
2947 swap ( iTo, i, idNodes, P );
2952 // Set nodes of the found bottom face in good order
2953 DUMPSO( " Found bottom face: ");
2954 i = SortQuadNodes( theMesh, idNodes );
2956 gp_Pnt Ptmp = P[ i ];
2961 // for ( int ii = 0; ii < 4; ii++ ) {
2962 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2963 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2966 // Gravity center of the top and bottom faces
2967 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2968 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2970 // Get direction from the bottom to the top face
2971 gp_Vec upDir ( aGCb, aGCt );
2972 Standard_Real upDirSize = upDir.Magnitude();
2973 if ( upDirSize <= gp::Resolution() ) return false;
2976 // Assure that the bottom face normal points up
2977 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2978 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2979 if ( Nb.Dot( upDir ) < 0 ) {
2980 DUMPSO( "Reverse bottom face");
2981 swap( 1, 3, idNodes, P );
2984 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2985 Standard_Real minDist = DBL_MAX;
2986 for ( i = 4; i < 8; i++ ) {
2987 // projection of P[i] to the plane defined by P[0] and upDir
2988 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2989 Standard_Real sqDist = P[0].SquareDistance( Pp );
2990 if ( sqDist < minDist ) {
2995 DUMPSO( "Set 4-th");
2996 swap ( 4, iMin, idNodes, P );
2998 // Set nodes of the top face in good order
2999 DUMPSO( "Sort top face");
3000 i = SortQuadNodes( theMesh, &idNodes[4] );
3003 gp_Pnt Ptmp = P[ i ];
3008 // Assure that direction of the top face normal is from the bottom face
3009 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
3010 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
3011 if ( Nt.Dot( upDir ) < 0 ) {
3012 DUMPSO( "Reverse top face");
3013 swap( 5, 7, idNodes, P );
3016 // DUMPSO( "OUTPUT: ========================================");
3017 // for ( i = 0; i < 8; i++ ) {
3018 // float *p = ugrid->GetPoint(idNodes[i]);
3019 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
3025 //================================================================================
3027 * \brief Return nodes linked to the given one
3028 * \param theNode - the node
3029 * \param linkedNodes - the found nodes
3030 * \param type - the type of elements to check
3032 * Medium nodes are ignored
3034 //================================================================================
3036 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
3037 TIDSortedElemSet & linkedNodes,
3038 SMDSAbs_ElementType type )
3040 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
3041 while ( elemIt->more() )
3043 const SMDS_MeshElement* elem = elemIt->next();
3044 if(elem->GetType() == SMDSAbs_0DElement)
3047 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
3048 if ( elem->GetType() == SMDSAbs_Volume )
3050 SMDS_VolumeTool vol( elem );
3051 while ( nodeIt->more() ) {
3052 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3053 if ( theNode != n && vol.IsLinked( theNode, n ))
3054 linkedNodes.insert( n );
3059 for ( int i = 0; nodeIt->more(); ++i ) {
3060 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3061 if ( n == theNode ) {
3062 int iBefore = i - 1;
3064 if ( elem->IsQuadratic() ) {
3065 int nb = elem->NbNodes() / 2;
3066 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
3067 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
3069 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
3070 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
3077 //=======================================================================
3078 //function : laplacianSmooth
3079 //purpose : pulls theNode toward the center of surrounding nodes directly
3080 // connected to that node along an element edge
3081 //=======================================================================
3083 void laplacianSmooth(const SMDS_MeshNode* theNode,
3084 const Handle(Geom_Surface)& theSurface,
3085 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3087 // find surrounding nodes
3089 TIDSortedElemSet nodeSet;
3090 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
3092 // compute new coodrs
3094 double coord[] = { 0., 0., 0. };
3095 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
3096 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
3097 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
3098 if ( theSurface.IsNull() ) { // smooth in 3D
3099 coord[0] += node->X();
3100 coord[1] += node->Y();
3101 coord[2] += node->Z();
3103 else { // smooth in 2D
3104 ASSERT( theUVMap.find( node ) != theUVMap.end() );
3105 gp_XY* uv = theUVMap[ node ];
3106 coord[0] += uv->X();
3107 coord[1] += uv->Y();
3110 int nbNodes = nodeSet.size();
3113 coord[0] /= nbNodes;
3114 coord[1] /= nbNodes;
3116 if ( !theSurface.IsNull() ) {
3117 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3118 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3119 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3125 coord[2] /= nbNodes;
3129 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3132 //=======================================================================
3133 //function : centroidalSmooth
3134 //purpose : pulls theNode toward the element-area-weighted centroid of the
3135 // surrounding elements
3136 //=======================================================================
3138 void centroidalSmooth(const SMDS_MeshNode* theNode,
3139 const Handle(Geom_Surface)& theSurface,
3140 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3142 gp_XYZ aNewXYZ(0.,0.,0.);
3143 SMESH::Controls::Area anAreaFunc;
3144 double totalArea = 0.;
3149 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3150 while ( elemIt->more() )
3152 const SMDS_MeshElement* elem = elemIt->next();
3155 gp_XYZ elemCenter(0.,0.,0.);
3156 SMESH::Controls::TSequenceOfXYZ aNodePoints;
3157 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3158 int nn = elem->NbNodes();
3159 if(elem->IsQuadratic()) nn = nn/2;
3161 //while ( itN->more() ) {
3163 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3165 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3166 aNodePoints.push_back( aP );
3167 if ( !theSurface.IsNull() ) { // smooth in 2D
3168 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3169 gp_XY* uv = theUVMap[ aNode ];
3170 aP.SetCoord( uv->X(), uv->Y(), 0. );
3174 double elemArea = anAreaFunc.GetValue( aNodePoints );
3175 totalArea += elemArea;
3177 aNewXYZ += elemCenter * elemArea;
3179 aNewXYZ /= totalArea;
3180 if ( !theSurface.IsNull() ) {
3181 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3182 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3187 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3190 //=======================================================================
3191 //function : getClosestUV
3192 //purpose : return UV of closest projection
3193 //=======================================================================
3195 static bool getClosestUV (Extrema_GenExtPS& projector,
3196 const gp_Pnt& point,
3199 projector.Perform( point );
3200 if ( projector.IsDone() ) {
3201 double u, v, minVal = DBL_MAX;
3202 for ( int i = projector.NbExt(); i > 0; i-- )
3203 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3204 if ( projector.SquareDistance( i ) < minVal ) {
3205 minVal = projector.SquareDistance( i );
3207 if ( projector.Value( i ) < minVal ) {
3208 minVal = projector.Value( i );
3210 projector.Point( i ).Parameter( u, v );
3212 result.SetCoord( u, v );
3218 //=======================================================================
3220 //purpose : Smooth theElements during theNbIterations or until a worst
3221 // element has aspect ratio <= theTgtAspectRatio.
3222 // Aspect Ratio varies in range [1.0, inf].
3223 // If theElements is empty, the whole mesh is smoothed.
3224 // theFixedNodes contains additionally fixed nodes. Nodes built
3225 // on edges and boundary nodes are always fixed.
3226 //=======================================================================
3228 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
3229 set<const SMDS_MeshNode*> & theFixedNodes,
3230 const SmoothMethod theSmoothMethod,
3231 const int theNbIterations,
3232 double theTgtAspectRatio,
3235 myLastCreatedElems.Clear();
3236 myLastCreatedNodes.Clear();
3238 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3240 if ( theTgtAspectRatio < 1.0 )
3241 theTgtAspectRatio = 1.0;
3243 const double disttol = 1.e-16;
3245 SMESH::Controls::AspectRatio aQualityFunc;
3247 SMESHDS_Mesh* aMesh = GetMeshDS();
3249 if ( theElems.empty() ) {
3250 // add all faces to theElems
3251 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3252 while ( fIt->more() ) {
3253 const SMDS_MeshElement* face = fIt->next();
3254 theElems.insert( theElems.end(), face );
3257 // get all face ids theElems are on
3258 set< int > faceIdSet;
3259 TIDSortedElemSet::iterator itElem;
3261 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3262 int fId = FindShape( *itElem );
3263 // check that corresponding submesh exists and a shape is face
3265 faceIdSet.find( fId ) == faceIdSet.end() &&
3266 aMesh->MeshElements( fId )) {
3267 TopoDS_Shape F = aMesh->IndexToShape( fId );
3268 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3269 faceIdSet.insert( fId );
3272 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3274 // ===============================================
3275 // smooth elements on each TopoDS_Face separately
3276 // ===============================================
3278 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3279 for ( ; fId != faceIdSet.rend(); ++fId ) {
3280 // get face surface and submesh
3281 Handle(Geom_Surface) surface;
3282 SMESHDS_SubMesh* faceSubMesh = 0;
3284 double fToler2 = 0, f,l;
3285 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3286 bool isUPeriodic = false, isVPeriodic = false;
3288 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3289 surface = BRep_Tool::Surface( face );
3290 faceSubMesh = aMesh->MeshElements( *fId );
3291 fToler2 = BRep_Tool::Tolerance( face );
3292 fToler2 *= fToler2 * 10.;
3293 isUPeriodic = surface->IsUPeriodic();
3296 isVPeriodic = surface->IsVPeriodic();
3299 surface->Bounds( u1, u2, v1, v2 );
3301 // ---------------------------------------------------------
3302 // for elements on a face, find movable and fixed nodes and
3303 // compute UV for them
3304 // ---------------------------------------------------------
3305 bool checkBoundaryNodes = false;
3306 bool isQuadratic = false;
3307 set<const SMDS_MeshNode*> setMovableNodes;
3308 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3309 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3310 list< const SMDS_MeshElement* > elemsOnFace;
3312 Extrema_GenExtPS projector;
3313 GeomAdaptor_Surface surfAdaptor;
3314 if ( !surface.IsNull() ) {
3315 surfAdaptor.Load( surface );
3316 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3318 int nbElemOnFace = 0;
3319 itElem = theElems.begin();
3320 // loop on not yet smoothed elements: look for elems on a face
3321 while ( itElem != theElems.end() ) {
3322 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3323 break; // all elements found
3325 const SMDS_MeshElement* elem = *itElem;
3326 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3327 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3331 elemsOnFace.push_back( elem );
3332 theElems.erase( itElem++ );
3336 isQuadratic = elem->IsQuadratic();
3338 // get movable nodes of elem
3339 const SMDS_MeshNode* node;
3340 SMDS_TypeOfPosition posType;
3341 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3342 int nn = 0, nbn = elem->NbNodes();
3343 if(elem->IsQuadratic())
3345 while ( nn++ < nbn ) {
3346 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3347 const SMDS_PositionPtr& pos = node->GetPosition();
3348 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3349 if (posType != SMDS_TOP_EDGE &&
3350 posType != SMDS_TOP_VERTEX &&
3351 theFixedNodes.find( node ) == theFixedNodes.end())
3353 // check if all faces around the node are on faceSubMesh
3354 // because a node on edge may be bound to face
3355 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3357 if ( faceSubMesh ) {
3358 while ( eIt->more() && all ) {
3359 const SMDS_MeshElement* e = eIt->next();
3360 all = faceSubMesh->Contains( e );
3364 setMovableNodes.insert( node );
3366 checkBoundaryNodes = true;
3368 if ( posType == SMDS_TOP_3DSPACE )
3369 checkBoundaryNodes = true;
3372 if ( surface.IsNull() )
3375 // get nodes to check UV
3376 list< const SMDS_MeshNode* > uvCheckNodes;
3377 itN = elem->nodesIterator();
3378 nn = 0; nbn = elem->NbNodes();
3379 if(elem->IsQuadratic())
3381 while ( nn++ < nbn ) {
3382 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3383 if ( uvMap.find( node ) == uvMap.end() )
3384 uvCheckNodes.push_back( node );
3385 // add nodes of elems sharing node
3386 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3387 // while ( eIt->more() ) {
3388 // const SMDS_MeshElement* e = eIt->next();
3389 // if ( e != elem ) {
3390 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3391 // while ( nIt->more() ) {
3392 // const SMDS_MeshNode* n =
3393 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3394 // if ( uvMap.find( n ) == uvMap.end() )
3395 // uvCheckNodes.push_back( n );
3401 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3402 for ( ; n != uvCheckNodes.end(); ++n ) {
3405 const SMDS_PositionPtr& pos = node->GetPosition();
3406 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3408 switch ( posType ) {
3409 case SMDS_TOP_FACE: {
3410 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3411 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3414 case SMDS_TOP_EDGE: {
3415 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3416 Handle(Geom2d_Curve) pcurve;
3417 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3418 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3419 if ( !pcurve.IsNull() ) {
3420 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3421 uv = pcurve->Value( u ).XY();
3425 case SMDS_TOP_VERTEX: {
3426 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3427 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3428 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3433 // check existing UV
3434 bool project = true;
3435 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3436 double dist1 = DBL_MAX, dist2 = 0;
3437 if ( posType != SMDS_TOP_3DSPACE ) {
3438 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3439 project = dist1 > fToler2;
3441 if ( project ) { // compute new UV
3443 if ( !getClosestUV( projector, pNode, newUV )) {
3444 MESSAGE("Node Projection Failed " << node);
3448 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3450 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3452 if ( posType != SMDS_TOP_3DSPACE )
3453 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3454 if ( dist2 < dist1 )
3458 // store UV in the map
3459 listUV.push_back( uv );
3460 uvMap.insert( make_pair( node, &listUV.back() ));
3462 } // loop on not yet smoothed elements
3464 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3465 checkBoundaryNodes = true;
3467 // fix nodes on mesh boundary
3469 if ( checkBoundaryNodes ) {
3470 map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3471 map< SMESH_TLink, int >::iterator link_nb;
3472 // put all elements links to linkNbMap
3473 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3474 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3475 const SMDS_MeshElement* elem = (*elemIt);
3476 int nbn = elem->NbCornerNodes();
3477 // loop on elem links: insert them in linkNbMap
3478 for ( int iN = 0; iN < nbn; ++iN ) {
3479 const SMDS_MeshNode* n1 = elem->GetNode( iN );
3480 const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3481 SMESH_TLink link( n1, n2 );
3482 link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3486 // remove nodes that are in links encountered only once from setMovableNodes
3487 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3488 if ( link_nb->second == 1 ) {
3489 setMovableNodes.erase( link_nb->first.node1() );
3490 setMovableNodes.erase( link_nb->first.node2() );
3495 // -----------------------------------------------------
3496 // for nodes on seam edge, compute one more UV ( uvMap2 );
3497 // find movable nodes linked to nodes on seam and which
3498 // are to be smoothed using the second UV ( uvMap2 )
3499 // -----------------------------------------------------
3501 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3502 if ( !surface.IsNull() ) {
3503 TopExp_Explorer eExp( face, TopAbs_EDGE );
3504 for ( ; eExp.More(); eExp.Next() ) {
3505 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3506 if ( !BRep_Tool::IsClosed( edge, face ))
3508 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3509 if ( !sm ) continue;
3510 // find out which parameter varies for a node on seam
3513 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3514 if ( pcurve.IsNull() ) continue;
3515 uv1 = pcurve->Value( f );
3517 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3518 if ( pcurve.IsNull() ) continue;
3519 uv2 = pcurve->Value( f );
3520 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3522 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3523 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3525 // get nodes on seam and its vertices
3526 list< const SMDS_MeshNode* > seamNodes;
3527 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3528 while ( nSeamIt->more() ) {
3529 const SMDS_MeshNode* node = nSeamIt->next();
3530 if ( !isQuadratic || !IsMedium( node ))
3531 seamNodes.push_back( node );
3533 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3534 for ( ; vExp.More(); vExp.Next() ) {
3535 sm = aMesh->MeshElements( vExp.Current() );
3537 nSeamIt = sm->GetNodes();
3538 while ( nSeamIt->more() )
3539 seamNodes.push_back( nSeamIt->next() );
3542 // loop on nodes on seam
3543 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3544 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3545 const SMDS_MeshNode* nSeam = *noSeIt;
3546 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3547 if ( n_uv == uvMap.end() )
3550 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3551 // set the second UV
3552 listUV.push_back( *n_uv->second );
3553 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3554 if ( uvMap2.empty() )
3555 uvMap2 = uvMap; // copy the uvMap contents
3556 uvMap2[ nSeam ] = &listUV.back();
3558 // collect movable nodes linked to ones on seam in nodesNearSeam
3559 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3560 while ( eIt->more() ) {
3561 const SMDS_MeshElement* e = eIt->next();
3562 int nbUseMap1 = 0, nbUseMap2 = 0;
3563 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3564 int nn = 0, nbn = e->NbNodes();
3565 if(e->IsQuadratic()) nbn = nbn/2;
3566 while ( nn++ < nbn )
3568 const SMDS_MeshNode* n =
3569 static_cast<const SMDS_MeshNode*>( nIt->next() );
3571 setMovableNodes.find( n ) == setMovableNodes.end() )
3573 // add only nodes being closer to uv2 than to uv1
3574 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3575 0.5 * ( n->Y() + nSeam->Y() ),
3576 0.5 * ( n->Z() + nSeam->Z() ));
3578 getClosestUV( projector, pMid, uv );
3579 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3580 nodesNearSeam.insert( n );
3586 // for centroidalSmooth all element nodes must
3587 // be on one side of a seam
3588 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3589 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3591 while ( nn++ < nbn ) {
3592 const SMDS_MeshNode* n =
3593 static_cast<const SMDS_MeshNode*>( nIt->next() );
3594 setMovableNodes.erase( n );
3598 } // loop on nodes on seam
3599 } // loop on edge of a face
3600 } // if ( !face.IsNull() )
3602 if ( setMovableNodes.empty() ) {
3603 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3604 continue; // goto next face
3612 double maxRatio = -1., maxDisplacement = -1.;
3613 set<const SMDS_MeshNode*>::iterator nodeToMove;
3614 for ( it = 0; it < theNbIterations; it++ ) {
3615 maxDisplacement = 0.;
3616 nodeToMove = setMovableNodes.begin();
3617 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3618 const SMDS_MeshNode* node = (*nodeToMove);
3619 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3622 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3623 if ( theSmoothMethod == LAPLACIAN )
3624 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3626 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3628 // node displacement
3629 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3630 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3631 if ( aDispl > maxDisplacement )
3632 maxDisplacement = aDispl;
3634 // no node movement => exit
3635 //if ( maxDisplacement < 1.e-16 ) {
3636 if ( maxDisplacement < disttol ) {
3637 MESSAGE("-- no node movement --");
3641 // check elements quality
3643 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3644 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3645 const SMDS_MeshElement* elem = (*elemIt);
3646 if ( !elem || elem->GetType() != SMDSAbs_Face )
3648 SMESH::Controls::TSequenceOfXYZ aPoints;
3649 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3650 double aValue = aQualityFunc.GetValue( aPoints );
3651 if ( aValue > maxRatio )
3655 if ( maxRatio <= theTgtAspectRatio ) {
3656 MESSAGE("-- quality achived --");
3659 if (it+1 == theNbIterations) {
3660 MESSAGE("-- Iteration limit exceeded --");
3662 } // smoothing iterations
3664 MESSAGE(" Face id: " << *fId <<
3665 " Nb iterstions: " << it <<
3666 " Displacement: " << maxDisplacement <<
3667 " Aspect Ratio " << maxRatio);
3669 // ---------------------------------------
3670 // new nodes positions are computed,
3671 // record movement in DS and set new UV
3672 // ---------------------------------------
3673 nodeToMove = setMovableNodes.begin();
3674 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3675 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3676 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3677 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3678 if ( node_uv != uvMap.end() ) {
3679 gp_XY* uv = node_uv->second;
3681 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3685 // move medium nodes of quadratic elements
3688 SMESH_MesherHelper helper( *GetMesh() );
3689 helper.SetSubShape( face );
3690 vector<const SMDS_MeshNode*> nodes;
3692 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3693 for ( ; elemIt != elemsOnFace.end(); ++elemIt )
3695 const SMDS_MeshElement* QF = *elemIt;
3696 if ( QF->IsQuadratic() )
3698 nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesElemIterator() ),
3699 SMDS_MeshElement::iterator() );
3700 nodes.push_back( nodes[0] );
3702 for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
3704 if ( !surface.IsNull() )
3706 gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
3707 gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
3708 gp_XY uv = helper.GetMiddleUV( surface, uv1, uv2 );
3709 xyz = surface->Value( uv.X(), uv.Y() );
3712 xyz = 0.5 * ( SMESH_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
3714 if (( SMESH_TNodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
3715 // we have to move a medium node
3716 aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
3722 } // loop on face ids
3726 //=======================================================================
3727 //function : isReverse
3728 //purpose : Return true if normal of prevNodes is not co-directied with
3729 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3730 // iNotSame is where prevNodes and nextNodes are different.
3731 // If result is true then future volume orientation is OK
3732 //=======================================================================
3734 static bool isReverse(const SMDS_MeshElement* face,
3735 const vector<const SMDS_MeshNode*>& prevNodes,
3736 const vector<const SMDS_MeshNode*>& nextNodes,
3740 SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3741 SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3742 gp_XYZ extrDir( pN - pP ), faceNorm;
3743 SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
3745 return faceNorm * extrDir < 0.0;
3748 //=======================================================================
3750 * \brief Create elements by sweeping an element
3751 * \param elem - element to sweep
3752 * \param newNodesItVec - nodes generated from each node of the element
3753 * \param newElems - generated elements
3754 * \param nbSteps - number of sweeping steps
3755 * \param srcElements - to append elem for each generated element
3757 //=======================================================================
3759 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3760 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3761 list<const SMDS_MeshElement*>& newElems,
3763 SMESH_SequenceOfElemPtr& srcElements)
3765 //MESSAGE("sweepElement " << nbSteps);
3766 SMESHDS_Mesh* aMesh = GetMeshDS();
3768 const int nbNodes = elem->NbNodes();
3769 const int nbCorners = elem->NbCornerNodes();
3770 SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3771 polyhedron creation !!! */
3772 // Loop on elem nodes:
3773 // find new nodes and detect same nodes indices
3774 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3775 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3776 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3777 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3779 int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3780 vector<int> sames(nbNodes);
3781 vector<bool> isSingleNode(nbNodes);
3783 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3784 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3785 const SMDS_MeshNode* node = nnIt->first;
3786 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3787 if ( listNewNodes.empty() )
3790 itNN [ iNode ] = listNewNodes.begin();
3791 prevNod[ iNode ] = node;
3792 nextNod[ iNode ] = listNewNodes.front();
3794 isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3795 corner node of linear */
3796 if ( prevNod[ iNode ] != nextNod [ iNode ])
3797 nbDouble += !isSingleNode[iNode];
3799 if( iNode < nbCorners ) { // check corners only
3800 if ( prevNod[ iNode ] == nextNod [ iNode ])
3801 sames[nbSame++] = iNode;
3803 iNotSameNode = iNode;
3807 if ( nbSame == nbNodes || nbSame > 2) {
3808 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3812 if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3814 // fix nodes order to have bottom normal external
3815 if ( baseType == SMDSEntity_Polygon )
3817 std::reverse( itNN.begin(), itNN.end() );
3818 std::reverse( prevNod.begin(), prevNod.end() );
3819 std::reverse( midlNod.begin(), midlNod.end() );
3820 std::reverse( nextNod.begin(), nextNod.end() );
3821 std::reverse( isSingleNode.begin(), isSingleNode.end() );
3825 const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3826 SMDS_MeshCell::applyInterlace( ind, itNN );
3827 SMDS_MeshCell::applyInterlace( ind, prevNod );
3828 SMDS_MeshCell::applyInterlace( ind, nextNod );
3829 SMDS_MeshCell::applyInterlace( ind, midlNod );
3830 SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3833 sames[nbSame] = iNotSameNode;
3834 for ( int j = 0; j <= nbSame; ++j )
3835 for ( size_t i = 0; i < ind.size(); ++i )
3836 if ( ind[i] == sames[j] )
3841 iNotSameNode = sames[nbSame];
3846 int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3848 iSameNode = sames[ nbSame-1 ];
3849 iBeforeSame = ( iSameNode + nbCorners - 1 ) % nbCorners;
3850 iAfterSame = ( iSameNode + 1 ) % nbCorners;
3851 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3854 // make new elements
3855 for (int iStep = 0; iStep < nbSteps; iStep++ )
3858 for ( iNode = 0; iNode < nbNodes; iNode++ )
3860 midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3861 nextNod[ iNode ] = *itNN[ iNode ]++;
3864 SMDS_MeshElement* aNewElem = 0;
3865 /*if(!elem->IsPoly())*/ {
3866 switch ( baseType ) {
3868 case SMDSEntity_Node: { // sweep NODE
3869 if ( nbSame == 0 ) {
3870 if ( isSingleNode[0] )
3871 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3873 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3879 case SMDSEntity_Edge: { // sweep EDGE
3880 if ( nbDouble == 0 )
3882 if ( nbSame == 0 ) // ---> quadrangle
3883 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3884 nextNod[ 1 ], nextNod[ 0 ] );
3885 else // ---> triangle
3886 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3887 nextNod[ iNotSameNode ] );
3889 else // ---> polygon
3891 vector<const SMDS_MeshNode*> poly_nodes;
3892 poly_nodes.push_back( prevNod[0] );
3893 poly_nodes.push_back( prevNod[1] );
3894 if ( prevNod[1] != nextNod[1] )
3896 if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3897 poly_nodes.push_back( nextNod[1] );
3899 if ( prevNod[0] != nextNod[0] )
3901 poly_nodes.push_back( nextNod[0] );
3902 if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3904 switch ( poly_nodes.size() ) {
3906 aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3909 aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3910 poly_nodes[ 2 ], poly_nodes[ 3 ]);
3913 aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3918 case SMDSEntity_Triangle: // TRIANGLE --->
3920 if ( nbDouble > 0 ) break;
3921 if ( nbSame == 0 ) // ---> pentahedron
3922 aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3923 nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3925 else if ( nbSame == 1 ) // ---> pyramid
3926 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3927 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3928 nextNod[ iSameNode ]);
3930 else // 2 same nodes: ---> tetrahedron
3931 aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3932 nextNod[ iNotSameNode ]);
3935 case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3939 if ( nbDouble+nbSame == 2 )
3941 if(nbSame==0) { // ---> quadratic quadrangle
3942 aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3943 prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3945 else { //(nbSame==1) // ---> quadratic triangle
3947 return; // medium node on axis
3949 else if(sames[0]==0)
3950 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3951 nextNod[2], midlNod[1], prevNod[2]);
3953 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3954 midlNod[0], nextNod[2], prevNod[2]);
3957 else if ( nbDouble == 3 )
3959 if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle
3960 aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3961 prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3968 case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3969 if ( nbDouble > 0 ) break;
3971 if ( nbSame == 0 ) // ---> hexahedron
3972 aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3973 nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3975 else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3976 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3977 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3978 nextNod[ iSameNode ]);
3979 newElems.push_back( aNewElem );
3980 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3981 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3982 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3984 else if ( nbSame == 2 ) { // ---> pentahedron
3985 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3986 // iBeforeSame is same too
3987 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3988 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3989 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3991 // iAfterSame is same too
3992 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3993 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3994 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3998 case SMDSEntity_Quad_Triangle: // sweep (Bi)Quadratic TRIANGLE --->
3999 case SMDSEntity_BiQuad_Triangle: /* ??? */ {
4000 if ( nbDouble+nbSame != 3 ) break;
4002 // ---> pentahedron with 15 nodes
4003 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4004 nextNod[0], nextNod[1], nextNod[2],
4005 prevNod[3], prevNod[4], prevNod[5],
4006 nextNod[3], nextNod[4], nextNod[5],
4007 midlNod[0], midlNod[1], midlNod[2]);
4009 else if(nbSame==1) {
4010 // ---> 2d order pyramid of 13 nodes
4011 int apex = iSameNode;
4012 int i0 = ( apex + 1 ) % nbCorners;
4013 int i1 = ( apex - 1 + nbCorners ) % nbCorners;
4017 aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
4018 nextNod[i0], nextNod[i1], prevNod[apex],
4019 prevNod[i01], midlNod[i0],
4020 nextNod[i01], midlNod[i1],
4021 prevNod[i1a], prevNod[i0a],
4022 nextNod[i0a], nextNod[i1a]);
4024 else if(nbSame==2) {
4025 // ---> 2d order tetrahedron of 10 nodes
4026 int n1 = iNotSameNode;
4027 int n2 = ( n1 + 1 ) % nbCorners;
4028 int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
4032 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
4033 prevNod[n12], prevNod[n23], prevNod[n31],
4034 midlNod[n1], nextNod[n12], nextNod[n31]);
4038 case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
4040 if ( nbDouble != 4 ) break;
4041 // ---> hexahedron with 20 nodes
4042 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4043 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4044 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4045 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4046 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
4048 else if(nbSame==1) {
4049 // ---> pyramid + pentahedron - can not be created since it is needed
4050 // additional middle node at the center of face
4051 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
4054 else if( nbSame == 2 ) {
4055 if ( nbDouble != 2 ) break;
4056 // ---> 2d order Pentahedron with 15 nodes
4058 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
4059 // iBeforeSame is same too
4066 // iAfterSame is same too
4076 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
4077 prevNod[n4], prevNod[n5], nextNod[n5],
4078 prevNod[n12], midlNod[n2], nextNod[n12],
4079 prevNod[n45], midlNod[n5], nextNod[n45],
4080 prevNod[n14], prevNod[n25], nextNod[n25]);
4084 case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
4086 if( nbSame == 0 && nbDouble == 9 ) {
4087 // ---> tri-quadratic hexahedron with 27 nodes
4088 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4089 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4090 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4091 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4092 midlNod[0], midlNod[1], midlNod[2], midlNod[3],
4093 prevNod[8], // bottom center
4094 midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4095 nextNod[8], // top center
4096 midlNod[8]);// elem center
4104 case SMDSEntity_Polygon: { // sweep POLYGON
4106 if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4107 // ---> hexagonal prism
4108 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4109 prevNod[3], prevNod[4], prevNod[5],
4110 nextNod[0], nextNod[1], nextNod[2],
4111 nextNod[3], nextNod[4], nextNod[5]);
4115 case SMDSEntity_Ball:
4123 if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4125 if ( baseType != SMDSEntity_Polygon )
4127 const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
4128 SMDS_MeshCell::applyInterlace( ind, prevNod );
4129 SMDS_MeshCell::applyInterlace( ind, nextNod );
4130 SMDS_MeshCell::applyInterlace( ind, midlNod );
4131 SMDS_MeshCell::applyInterlace( ind, itNN );
4132 SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4133 baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4135 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4136 vector<int> quantities (nbNodes + 2);
4137 polyedre_nodes.clear();
4141 for (int inode = 0; inode < nbNodes; inode++)
4142 polyedre_nodes.push_back( prevNod[inode] );
4143 quantities.push_back( nbNodes );
4146 polyedre_nodes.push_back( nextNod[0] );
4147 for (int inode = nbNodes; inode-1; --inode )
4148 polyedre_nodes.push_back( nextNod[inode-1] );
4149 quantities.push_back( nbNodes );
4152 for (int iface = 0; iface < nbNodes; iface++)
4154 const int prevNbNodes = polyedre_nodes.size();
4155 int inextface = (iface+1) % nbNodes;
4156 polyedre_nodes.push_back( prevNod[inextface] );
4157 polyedre_nodes.push_back( prevNod[iface] );
4158 if ( prevNod[iface] != nextNod[iface] )
4160 if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
4161 polyedre_nodes.push_back( nextNod[iface] );
4163 if ( prevNod[inextface] != nextNod[inextface] )
4165 polyedre_nodes.push_back( nextNod[inextface] );
4166 if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
4168 const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4169 if ( nbFaceNodes > 2 )
4170 quantities.push_back( nbFaceNodes );
4171 else // degenerated face
4172 polyedre_nodes.resize( prevNbNodes );
4174 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4178 newElems.push_back( aNewElem );
4179 myLastCreatedElems.Append(aNewElem);
4180 srcElements.Append( elem );
4183 // set new prev nodes
4184 for ( iNode = 0; iNode < nbNodes; iNode++ )
4185 prevNod[ iNode ] = nextNod[ iNode ];
4190 //=======================================================================
4192 * \brief Create 1D and 2D elements around swept elements
4193 * \param mapNewNodes - source nodes and ones generated from them
4194 * \param newElemsMap - source elements and ones generated from them
4195 * \param elemNewNodesMap - nodes generated from each node of each element
4196 * \param elemSet - all swept elements
4197 * \param nbSteps - number of sweeping steps
4198 * \param srcElements - to append elem for each generated element
4200 //=======================================================================
4202 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
4203 TElemOfElemListMap & newElemsMap,
4204 TElemOfVecOfNnlmiMap & elemNewNodesMap,
4205 TIDSortedElemSet& elemSet,
4207 SMESH_SequenceOfElemPtr& srcElements)
4209 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4210 SMESHDS_Mesh* aMesh = GetMeshDS();
4212 // Find nodes belonging to only one initial element - sweep them into edges.
4214 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4215 for ( ; nList != mapNewNodes.end(); nList++ )
4217 const SMDS_MeshNode* node =
4218 static_cast<const SMDS_MeshNode*>( nList->first );
4219 if ( newElemsMap.count( node ))
4220 continue; // node was extruded into edge
4221 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4222 int nbInitElems = 0;
4223 const SMDS_MeshElement* el = 0;
4224 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4225 while ( eIt->more() && nbInitElems < 2 ) {
4227 SMDSAbs_ElementType type = el->GetType();
4228 if ( type == SMDSAbs_Volume || type < highType ) continue;
4229 if ( type > highType ) {
4233 nbInitElems += elemSet.count(el);
4235 if ( nbInitElems < 2 ) {
4236 bool NotCreateEdge = el && el->IsMediumNode(node);
4237 if(!NotCreateEdge) {
4238 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4239 list<const SMDS_MeshElement*> newEdges;
4240 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4245 // Make a ceiling for each element ie an equal element of last new nodes.
4246 // Find free links of faces - make edges and sweep them into faces.
4248 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
4249 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4250 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4252 const SMDS_MeshElement* elem = itElem->first;
4253 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4255 if(itElem->second.size()==0) continue;
4257 const bool isQuadratic = elem->IsQuadratic();
4259 if ( elem->GetType() == SMDSAbs_Edge ) {
4260 // create a ceiling edge
4261 if ( !isQuadratic ) {
4262 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4263 vecNewNodes[ 1 ]->second.back())) {
4264 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4265 vecNewNodes[ 1 ]->second.back()));
4266 srcElements.Append( elem );
4270 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4271 vecNewNodes[ 1 ]->second.back(),
4272 vecNewNodes[ 2 ]->second.back())) {
4273 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4274 vecNewNodes[ 1 ]->second.back(),
4275 vecNewNodes[ 2 ]->second.back()));
4276 srcElements.Append( elem );
4280 if ( elem->GetType() != SMDSAbs_Face )
4283 bool hasFreeLinks = false;
4285 TIDSortedElemSet avoidSet;
4286 avoidSet.insert( elem );
4288 set<const SMDS_MeshNode*> aFaceLastNodes;
4289 int iNode, nbNodes = vecNewNodes.size();
4290 if ( !isQuadratic ) {
4291 // loop on the face nodes
4292 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4293 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4294 // look for free links of the face
4295 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4296 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4297 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4298 // check if a link n1-n2 is free
4299 if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4300 hasFreeLinks = true;
4301 // make a new edge and a ceiling for a new edge
4302 const SMDS_MeshElement* edge;
4303 if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
4304 myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
4305 srcElements.Append( myLastCreatedElems.Last() );
4307 n1 = vecNewNodes[ iNode ]->second.back();
4308 n2 = vecNewNodes[ iNext ]->second.back();
4309 if ( !aMesh->FindEdge( n1, n2 )) {
4310 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
4311 srcElements.Append( edge );
4316 else { // elem is quadratic face
4317 int nbn = nbNodes/2;
4318 for ( iNode = 0; iNode < nbn; iNode++ ) {
4319 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4320 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4321 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4322 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4323 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4324 // check if a link is free
4325 if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4326 ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4327 ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4328 hasFreeLinks = true;
4329 // make an edge and a ceiling for a new edge
4331 if ( !aMesh->FindEdge( n1, n2, n3 )) {
4332 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4333 srcElements.Append( elem );
4335 n1 = vecNewNodes[ iNode ]->second.back();
4336 n2 = vecNewNodes[ iNext ]->second.back();
4337 n3 = vecNewNodes[ iNode+nbn ]->second.back();
4338 if ( !aMesh->FindEdge( n1, n2, n3 )) {
4339 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4340 srcElements.Append( elem );
4344 for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4345 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4349 // sweep free links into faces
4351 if ( hasFreeLinks ) {
4352 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4353 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4355 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4356 set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
4357 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4358 initNodeSet.insert( vecNewNodes[ iNode ]->first );
4359 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4361 if ( isQuadratic && nbNodes % 2 ) { // node set for the case of a biquadratic
4362 initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
4363 initNodeSetNoCenter.erase( vecNewNodes.back()->first );
4365 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4366 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4367 std::advance( v, volNb );
4368 // find indices of free faces of a volume and their source edges
4369 list< int > freeInd;
4370 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4371 SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4372 int iF, nbF = vTool.NbFaces();
4373 for ( iF = 0; iF < nbF; iF ++ ) {
4374 if (vTool.IsFreeFace( iF ) &&
4375 vTool.GetFaceNodes( iF, faceNodeSet ) &&
4376 initNodeSet != faceNodeSet) // except an initial face
4378 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4380 if ( faceNodeSet == initNodeSetNoCenter )
4382 freeInd.push_back( iF );
4383 // find source edge of a free face iF
4384 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4385 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4386 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4387 initNodeSet.begin(), initNodeSet.end(),
4388 commonNodes.begin());
4389 if ( (*v)->IsQuadratic() )
4390 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4392 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4394 if ( !srcEdges.back() )
4396 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4397 << iF << " of volume #" << vTool.ID() << endl;
4402 if ( freeInd.empty() )
4405 // create faces for all steps;
4406 // if such a face has been already created by sweep of edge,
4407 // assure that its orientation is OK
4408 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4409 vTool.Set( *v, /*ignoreCentralNodes=*/false );
4410 vTool.SetExternalNormal();
4411 const int nextShift = vTool.IsForward() ? +1 : -1;
4412 list< int >::iterator ind = freeInd.begin();
4413 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4414 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4416 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4417 int nbn = vTool.NbFaceNodes( *ind );
4418 const SMDS_MeshElement * f = 0;
4419 if ( nbn == 3 ) ///// triangle
4421 f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4423 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4425 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4427 nodes[ 1 + nextShift ] };
4429 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4431 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4435 else if ( nbn == 4 ) ///// quadrangle
4437 f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4439 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4441 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4442 nodes[ 2 ], nodes[ 2+nextShift ] };
4444 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4446 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4447 newOrder[ 2 ], newOrder[ 3 ]));
4450 else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4452 f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4454 nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4456 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4458 nodes[2 + 2*nextShift],
4459 nodes[3 - 2*nextShift],
4461 nodes[3 + 2*nextShift]};
4463 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4465 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4473 else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4475 f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4476 nodes[1], nodes[3], nodes[5], nodes[7] );
4478 nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4480 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4481 nodes[4 - 2*nextShift],
4483 nodes[4 + 2*nextShift],
4485 nodes[5 - 2*nextShift],
4487 nodes[5 + 2*nextShift] };
4489 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4491 myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4492 newOrder[ 2 ], newOrder[ 3 ],
4493 newOrder[ 4 ], newOrder[ 5 ],
4494 newOrder[ 6 ], newOrder[ 7 ]));
4497 else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4499 f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4500 SMDSAbs_Face, /*noMedium=*/false);
4502 nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4504 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4505 nodes[4 - 2*nextShift],
4507 nodes[4 + 2*nextShift],
4509 nodes[5 - 2*nextShift],
4511 nodes[5 + 2*nextShift],
4514 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4516 myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4517 newOrder[ 2 ], newOrder[ 3 ],
4518 newOrder[ 4 ], newOrder[ 5 ],
4519 newOrder[ 6 ], newOrder[ 7 ],
4523 else //////// polygon
4525 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4526 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4528 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4530 if ( !vTool.IsForward() )
4531 std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4533 aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4535 AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4539 while ( srcElements.Length() < myLastCreatedElems.Length() )
4540 srcElements.Append( *srcEdge );
4542 } // loop on free faces
4544 // go to the next volume
4546 while ( iVol++ < nbVolumesByStep ) v++;
4549 } // loop on volumes of one step
4550 } // sweep free links into faces
4552 // Make a ceiling face with a normal external to a volume
4554 // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
4555 SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4556 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4558 if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
4559 aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
4560 iF = lastVol.GetFaceIndex( aFaceLastNodes );
4563 lastVol.SetExternalNormal();
4564 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4565 int nbn = lastVol.NbFaceNodes( iF );
4566 // we do not use this->AddElement() because nodes are interlaced
4567 vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
4568 if ( !hasFreeLinks ||
4569 !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
4572 myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] ));
4574 else if ( nbn == 4 )
4575 myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3]));
4577 else if ( nbn == 6 && isQuadratic )
4578 myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4579 nodes[1], nodes[3], nodes[5]));
4580 else if ( nbn == 7 && isQuadratic )
4581 myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4],
4582 nodes[1], nodes[3], nodes[5], nodes[6]));
4583 else if ( nbn == 8 && isQuadratic )
4584 myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4585 nodes[1], nodes[3], nodes[5], nodes[7]));
4586 else if ( nbn == 9 && isQuadratic )
4587 myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6],
4588 nodes[1], nodes[3], nodes[5], nodes[7],
4591 myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec ));
4593 while ( srcElements.Length() < myLastCreatedElems.Length() )
4594 srcElements.Append( elem );
4597 } // loop on swept elements
4600 //=======================================================================
4601 //function : RotationSweep
4603 //=======================================================================
4605 SMESH_MeshEditor::PGroupIDs
4606 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4607 const gp_Ax1& theAxis,
4608 const double theAngle,
4609 const int theNbSteps,
4610 const double theTol,
4611 const bool theMakeGroups,
4612 const bool theMakeWalls)
4614 myLastCreatedElems.Clear();
4615 myLastCreatedNodes.Clear();
4617 // source elements for each generated one
4618 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4620 MESSAGE( "RotationSweep()");
4622 aTrsf.SetRotation( theAxis, theAngle );
4624 aTrsf2.SetRotation( theAxis, theAngle/2. );
4626 gp_Lin aLine( theAxis );
4627 double aSqTol = theTol * theTol;
4629 SMESHDS_Mesh* aMesh = GetMeshDS();
4631 TNodeOfNodeListMap mapNewNodes;
4632 TElemOfVecOfNnlmiMap mapElemNewNodes;
4633 TElemOfElemListMap newElemsMap;
4635 const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4636 myMesh->NbFaces(ORDER_QUADRATIC) +
4637 myMesh->NbVolumes(ORDER_QUADRATIC) );
4639 TIDSortedElemSet::iterator itElem;
4640 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4641 const SMDS_MeshElement* elem = *itElem;
4642 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4644 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4645 newNodesItVec.reserve( elem->NbNodes() );
4647 // loop on elem nodes
4648 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4649 while ( itN->more() )
4651 // check if a node has been already sweeped
4652 const SMDS_MeshNode* node = cast2Node( itN->next() );
4654 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4656 aXYZ.Coord( coord[0], coord[1], coord[2] );
4657 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4659 TNodeOfNodeListMapItr nIt =
4660 mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4661 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4662 if ( listNewNodes.empty() )
4664 // check if we are to create medium nodes between corner ones
4665 bool needMediumNodes = false;
4666 if ( isQuadraticMesh )
4668 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4669 while (it->more() && !needMediumNodes )
4671 const SMDS_MeshElement* invElem = it->next();
4672 if ( invElem != elem && !theElems.count( invElem )) continue;
4673 needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4674 if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4675 needMediumNodes = true;
4680 const SMDS_MeshNode * newNode = node;
4681 for ( int i = 0; i < theNbSteps; i++ ) {
4683 if ( needMediumNodes ) // create a medium node
4685 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4686 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4687 myLastCreatedNodes.Append(newNode);
4688 srcNodes.Append( node );
4689 listNewNodes.push_back( newNode );
4690 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4693 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4695 // create a corner node
4696 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4697 myLastCreatedNodes.Append(newNode);
4698 srcNodes.Append( node );
4699 listNewNodes.push_back( newNode );
4702 listNewNodes.push_back( newNode );
4703 // if ( needMediumNodes )
4704 // listNewNodes.push_back( newNode );
4708 newNodesItVec.push_back( nIt );
4710 // make new elements
4711 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4715 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4717 PGroupIDs newGroupIDs;
4718 if ( theMakeGroups )
4719 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4725 //=======================================================================
4726 //function : CreateNode
4728 //=======================================================================
4729 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4732 const double tolnode,
4733 SMESH_SequenceOfNode& aNodes)
4735 // myLastCreatedElems.Clear();
4736 // myLastCreatedNodes.Clear();
4739 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4741 // try to search in sequence of existing nodes
4742 // if aNodes.Length()>0 we 'nave to use given sequence
4743 // else - use all nodes of mesh
4744 if(aNodes.Length()>0) {
4746 for(i=1; i<=aNodes.Length(); i++) {
4747 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4748 if(P1.Distance(P2)<tolnode)
4749 return aNodes.Value(i);
4753 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4754 while(itn->more()) {
4755 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4756 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4757 if(P1.Distance(P2)<tolnode)
4762 // create new node and return it
4763 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4764 //myLastCreatedNodes.Append(NewNode);
4769 //=======================================================================
4770 //function : ExtrusionSweep
4772 //=======================================================================
4774 SMESH_MeshEditor::PGroupIDs
4775 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4776 const gp_Vec& theStep,
4777 const int theNbSteps,
4778 TElemOfElemListMap& newElemsMap,
4779 const bool theMakeGroups,
4781 const double theTolerance)
4783 ExtrusParam aParams;
4784 aParams.myDir = gp_Dir(theStep);
4785 aParams.myNodes.Clear();
4786 aParams.mySteps = new TColStd_HSequenceOfReal;
4788 for(i=1; i<=theNbSteps; i++)
4789 aParams.mySteps->Append(theStep.Magnitude());
4792 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4796 //=======================================================================
4797 //function : ExtrusionSweep
4799 //=======================================================================
4801 SMESH_MeshEditor::PGroupIDs
4802 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4803 ExtrusParam& theParams,
4804 TElemOfElemListMap& newElemsMap,
4805 const bool theMakeGroups,
4807 const double theTolerance)
4809 myLastCreatedElems.Clear();
4810 myLastCreatedNodes.Clear();
4812 // source elements for each generated one
4813 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4815 SMESHDS_Mesh* aMesh = GetMeshDS();
4817 int nbsteps = theParams.mySteps->Length();
4819 TNodeOfNodeListMap mapNewNodes;
4820 //TNodeOfNodeVecMap mapNewNodes;
4821 TElemOfVecOfNnlmiMap mapElemNewNodes;
4822 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4824 const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4825 myMesh->NbFaces(ORDER_QUADRATIC) +
4826 myMesh->NbVolumes(ORDER_QUADRATIC) );
4828 TIDSortedElemSet::iterator itElem;
4829 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4830 // check element type
4831 const SMDS_MeshElement* elem = *itElem;
4832 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4835 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4836 newNodesItVec.reserve( elem->NbNodes() );
4838 // loop on elem nodes
4839 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4840 while ( itN->more() )
4842 // check if a node has been already sweeped
4843 const SMDS_MeshNode* node = cast2Node( itN->next() );
4844 TNodeOfNodeListMap::iterator nIt =
4845 mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4846 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4847 if ( listNewNodes.empty() )
4851 // check if we are to create medium nodes between corner ones
4852 bool needMediumNodes = false;
4853 if ( isQuadraticMesh )
4855 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4856 while (it->more() && !needMediumNodes )
4858 const SMDS_MeshElement* invElem = it->next();
4859 if ( invElem != elem && !theElems.count( invElem )) continue;
4860 needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4861 if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4862 needMediumNodes = true;
4866 double coord[] = { node->X(), node->Y(), node->Z() };
4867 for ( int i = 0; i < nbsteps; i++ )
4869 if ( needMediumNodes ) // create a medium node
4871 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4872 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4873 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4874 if( theFlags & EXTRUSION_FLAG_SEW ) {
4875 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4876 theTolerance, theParams.myNodes);
4877 listNewNodes.push_back( newNode );
4880 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4881 myLastCreatedNodes.Append(newNode);
4882 srcNodes.Append( node );
4883 listNewNodes.push_back( newNode );
4886 // create a corner node
4887 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4888 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4889 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4890 if( theFlags & EXTRUSION_FLAG_SEW ) {
4891 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4892 theTolerance, theParams.myNodes);
4893 listNewNodes.push_back( newNode );
4896 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4897 myLastCreatedNodes.Append(newNode);
4898 srcNodes.Append( node );
4899 listNewNodes.push_back( newNode );
4903 newNodesItVec.push_back( nIt );
4905 // make new elements
4906 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4909 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4910 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4912 PGroupIDs newGroupIDs;
4913 if ( theMakeGroups )
4914 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4919 //=======================================================================
4920 //function : ExtrusionAlongTrack
4922 //=======================================================================
4923 SMESH_MeshEditor::Extrusion_Error
4924 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4925 SMESH_subMesh* theTrack,
4926 const SMDS_MeshNode* theN1,
4927 const bool theHasAngles,
4928 list<double>& theAngles,
4929 const bool theLinearVariation,
4930 const bool theHasRefPoint,
4931 const gp_Pnt& theRefPoint,
4932 const bool theMakeGroups)
4934 MESSAGE("ExtrusionAlongTrack");
4935 myLastCreatedElems.Clear();
4936 myLastCreatedNodes.Clear();
4939 std::list<double> aPrms;
4940 TIDSortedElemSet::iterator itElem;
4943 TopoDS_Edge aTrackEdge;
4944 TopoDS_Vertex aV1, aV2;
4946 SMDS_ElemIteratorPtr aItE;
4947 SMDS_NodeIteratorPtr aItN;
4948 SMDSAbs_ElementType aTypeE;
4950 TNodeOfNodeListMap mapNewNodes;
4953 aNbE = theElements.size();
4956 return EXTR_NO_ELEMENTS;
4958 // 1.1 Track Pattern
4961 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4963 aItE = pSubMeshDS->GetElements();
4964 while ( aItE->more() ) {
4965 const SMDS_MeshElement* pE = aItE->next();
4966 aTypeE = pE->GetType();
4967 // Pattern must contain links only
4968 if ( aTypeE != SMDSAbs_Edge )
4969 return EXTR_PATH_NOT_EDGE;
4972 list<SMESH_MeshEditor_PathPoint> fullList;
4974 const TopoDS_Shape& aS = theTrack->GetSubShape();
4975 // Sub-shape for the Pattern must be an Edge or Wire
4976 if( aS.ShapeType() == TopAbs_EDGE ) {
4977 aTrackEdge = TopoDS::Edge( aS );
4978 // the Edge must not be degenerated
4979 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4980 return EXTR_BAD_PATH_SHAPE;
4981 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4982 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4983 const SMDS_MeshNode* aN1 = aItN->next();
4984 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4985 const SMDS_MeshNode* aN2 = aItN->next();
4986 // starting node must be aN1 or aN2
4987 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4988 return EXTR_BAD_STARTING_NODE;
4989 aItN = pSubMeshDS->GetNodes();
4990 while ( aItN->more() ) {
4991 const SMDS_MeshNode* pNode = aItN->next();
4992 const SMDS_EdgePosition* pEPos =
4993 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4994 double aT = pEPos->GetUParameter();
4995 aPrms.push_back( aT );
4997 //Extrusion_Error err =
4998 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4999 } else if( aS.ShapeType() == TopAbs_WIRE ) {
5000 list< SMESH_subMesh* > LSM;
5001 TopTools_SequenceOfShape Edges;
5002 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
5003 while(itSM->more()) {
5004 SMESH_subMesh* SM = itSM->next();
5006 const TopoDS_Shape& aS = SM->GetSubShape();
5009 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5010 int startNid = theN1->GetID();
5011 TColStd_MapOfInteger UsedNums;
5013 int NbEdges = Edges.Length();
5015 for(; i<=NbEdges; i++) {
5017 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5018 for(; itLSM!=LSM.end(); itLSM++) {
5020 if(UsedNums.Contains(k)) continue;
5021 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5022 SMESH_subMesh* locTrack = *itLSM;
5023 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5024 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5025 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5026 const SMDS_MeshNode* aN1 = aItN->next();
5027 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5028 const SMDS_MeshNode* aN2 = aItN->next();
5029 // starting node must be aN1 or aN2
5030 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5031 // 2. Collect parameters on the track edge
5033 aItN = locMeshDS->GetNodes();
5034 while ( aItN->more() ) {
5035 const SMDS_MeshNode* pNode = aItN->next();
5036 const SMDS_EdgePosition* pEPos =
5037 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5038 double aT = pEPos->GetUParameter();
5039 aPrms.push_back( aT );
5041 list<SMESH_MeshEditor_PathPoint> LPP;
5042 //Extrusion_Error err =
5043 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5044 LLPPs.push_back(LPP);
5046 // update startN for search following egde
5047 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5048 else startNid = aN1->GetID();
5052 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5053 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5054 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5055 for(; itPP!=firstList.end(); itPP++) {
5056 fullList.push_back( *itPP );
5058 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5059 fullList.pop_back();
5061 for(; itLLPP!=LLPPs.end(); itLLPP++) {
5062 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5063 itPP = currList.begin();
5064 SMESH_MeshEditor_PathPoint PP2 = currList.front();
5065 gp_Dir D1 = PP1.Tangent();
5066 gp_Dir D2 = PP2.Tangent();
5067 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5068 (D1.Z()+D2.Z())/2 ) );
5069 PP1.SetTangent(Dnew);
5070 fullList.push_back(PP1);
5072 for(; itPP!=firstList.end(); itPP++) {
5073 fullList.push_back( *itPP );
5075 PP1 = fullList.back();
5076 fullList.pop_back();
5078 // if wire not closed
5079 fullList.push_back(PP1);
5083 return EXTR_BAD_PATH_SHAPE;
5086 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5087 theHasRefPoint, theRefPoint, theMakeGroups);
5091 //=======================================================================
5092 //function : ExtrusionAlongTrack
5094 //=======================================================================
5095 SMESH_MeshEditor::Extrusion_Error
5096 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
5097 SMESH_Mesh* theTrack,
5098 const SMDS_MeshNode* theN1,
5099 const bool theHasAngles,
5100 list<double>& theAngles,
5101 const bool theLinearVariation,
5102 const bool theHasRefPoint,
5103 const gp_Pnt& theRefPoint,
5104 const bool theMakeGroups)
5106 myLastCreatedElems.Clear();
5107 myLastCreatedNodes.Clear();
5110 std::list<double> aPrms;
5111 TIDSortedElemSet::iterator itElem;
5114 TopoDS_Edge aTrackEdge;
5115 TopoDS_Vertex aV1, aV2;
5117 SMDS_ElemIteratorPtr aItE;
5118 SMDS_NodeIteratorPtr aItN;
5119 SMDSAbs_ElementType aTypeE;
5121 TNodeOfNodeListMap mapNewNodes;
5124 aNbE = theElements.size();
5127 return EXTR_NO_ELEMENTS;
5129 // 1.1 Track Pattern
5132 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
5134 aItE = pMeshDS->elementsIterator();
5135 while ( aItE->more() ) {
5136 const SMDS_MeshElement* pE = aItE->next();
5137 aTypeE = pE->GetType();
5138 // Pattern must contain links only
5139 if ( aTypeE != SMDSAbs_Edge )
5140 return EXTR_PATH_NOT_EDGE;
5143 list<SMESH_MeshEditor_PathPoint> fullList;
5145 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
5147 if( aS == SMESH_Mesh::PseudoShape() ) {
5148 //Mesh without shape
5149 const SMDS_MeshNode* currentNode = NULL;
5150 const SMDS_MeshNode* prevNode = theN1;
5151 std::vector<const SMDS_MeshNode*> aNodesList;
5152 aNodesList.push_back(theN1);
5153 int nbEdges = 0, conn=0;
5154 const SMDS_MeshElement* prevElem = NULL;
5155 const SMDS_MeshElement* currentElem = NULL;
5156 int totalNbEdges = theTrack->NbEdges();
5157 SMDS_ElemIteratorPtr nIt;
5160 if( !theTrack->GetMeshDS()->Contains(theN1) ) {
5161 return EXTR_BAD_STARTING_NODE;
5164 conn = nbEdgeConnectivity(theN1);
5166 return EXTR_PATH_NOT_EDGE;
5168 aItE = theN1->GetInverseElementIterator();
5169 prevElem = aItE->next();
5170 currentElem = prevElem;
5172 if(totalNbEdges == 1 ) {
5173 nIt = currentElem->nodesIterator();
5174 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5175 if(currentNode == prevNode)
5176 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5177 aNodesList.push_back(currentNode);
5179 nIt = currentElem->nodesIterator();
5180 while( nIt->more() ) {
5181 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5182 if(currentNode == prevNode)
5183 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5184 aNodesList.push_back(currentNode);
5186 //case of the closed mesh
5187 if(currentNode == theN1) {
5192 conn = nbEdgeConnectivity(currentNode);
5194 return EXTR_PATH_NOT_EDGE;
5195 }else if( conn == 1 && nbEdges > 0 ) {
5200 prevNode = currentNode;
5201 aItE = currentNode->GetInverseElementIterator();
5202 currentElem = aItE->next();
5203 if( currentElem == prevElem)
5204 currentElem = aItE->next();
5205 nIt = currentElem->nodesIterator();
5206 prevElem = currentElem;
5212 if(nbEdges != totalNbEdges)
5213 return EXTR_PATH_NOT_EDGE;
5215 TopTools_SequenceOfShape Edges;
5216 double x1,x2,y1,y2,z1,z2;
5217 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5218 int startNid = theN1->GetID();
5219 for(int i = 1; i < aNodesList.size(); i++) {
5220 x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5221 y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5222 z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5223 TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5224 list<SMESH_MeshEditor_PathPoint> LPP;
5226 MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5227 LLPPs.push_back(LPP);
5228 if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5229 else startNid = aNodesList[i-1]->GetID();
5233 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5234 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5235 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5236 for(; itPP!=firstList.end(); itPP++) {
5237 fullList.push_back( *itPP );
5240 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5241 SMESH_MeshEditor_PathPoint PP2;
5242 fullList.pop_back();
5244 for(; itLLPP!=LLPPs.end(); itLLPP++) {
5245 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5246 itPP = currList.begin();
5247 PP2 = currList.front();
5248 gp_Dir D1 = PP1.Tangent();
5249 gp_Dir D2 = PP2.Tangent();
5250 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5251 (D1.Z()+D2.Z())/2 ) );
5252 PP1.SetTangent(Dnew);
5253 fullList.push_back(PP1);
5255 for(; itPP!=currList.end(); itPP++) {
5256 fullList.push_back( *itPP );
5258 PP1 = fullList.back();
5259 fullList.pop_back();
5261 fullList.push_back(PP1);
5263 } // Sub-shape for the Pattern must be an Edge or Wire
5264 else if( aS.ShapeType() == TopAbs_EDGE ) {
5265 aTrackEdge = TopoDS::Edge( aS );
5266 // the Edge must not be degenerated
5267 if ( BRep_Tool::Degenerated( aTrackEdge ) )
5268 return EXTR_BAD_PATH_SHAPE;
5269 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5270 const SMDS_MeshNode* aN1 = 0;
5271 const SMDS_MeshNode* aN2 = 0;
5272 if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
5273 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5276 if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
5277 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5280 // starting node must be aN1 or aN2
5281 if ( !( aN1 == theN1 || aN2 == theN1 ) )
5282 return EXTR_BAD_STARTING_NODE;
5283 aItN = pMeshDS->nodesIterator();
5284 while ( aItN->more() ) {
5285 const SMDS_MeshNode* pNode = aItN->next();
5286 if( pNode==aN1 || pNode==aN2 ) continue;
5287 const SMDS_EdgePosition* pEPos =
5288 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5289 double aT = pEPos->GetUParameter();
5290 aPrms.push_back( aT );
5292 //Extrusion_Error err =
5293 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5295 else if( aS.ShapeType() == TopAbs_WIRE ) {
5296 list< SMESH_subMesh* > LSM;
5297 TopTools_SequenceOfShape Edges;
5298 TopExp_Explorer eExp(aS, TopAbs_EDGE);
5299 for(; eExp.More(); eExp.Next()) {
5300 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5301 if( BRep_Tool::Degenerated(E) ) continue;
5302 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5308 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5309 TopoDS_Vertex aVprev;
5310 TColStd_MapOfInteger UsedNums;
5311 int NbEdges = Edges.Length();
5313 for(; i<=NbEdges; i++) {
5315 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5316 for(; itLSM!=LSM.end(); itLSM++) {
5318 if(UsedNums.Contains(k)) continue;
5319 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5320 SMESH_subMesh* locTrack = *itLSM;
5321 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5322 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5323 bool aN1isOK = false, aN2isOK = false;
5324 if ( aVprev.IsNull() ) {
5325 // if previous vertex is not yet defined, it means that we in the beginning of wire
5326 // and we have to find initial vertex corresponding to starting node theN1
5327 const SMDS_MeshNode* aN1 = 0;
5328 const SMDS_MeshNode* aN2 = 0;
5330 if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
5331 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5334 if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
5335 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5338 // starting node must be aN1 or aN2
5339 aN1isOK = ( aN1 && aN1 == theN1 );
5340 aN2isOK = ( aN2 && aN2 == theN1 );
5343 // we have specified ending vertex of the previous edge on the previous iteration
5344 // and we have just to check that it corresponds to any vertex in current segment
5345 aN1isOK = aVprev.IsSame( aV1 );
5346 aN2isOK = aVprev.IsSame( aV2 );
5348 if ( !aN1isOK && !aN2isOK ) continue;
5349 // 2. Collect parameters on the track edge
5351 aItN = locMeshDS->GetNodes();
5352 while ( aItN->more() ) {
5353 const SMDS_MeshNode* pNode = aItN->next();
5354 const SMDS_EdgePosition* pEPos =
5355 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5356 double aT = pEPos->GetUParameter();
5357 aPrms.push_back( aT );
5359 list<SMESH_MeshEditor_PathPoint> LPP;
5360 //Extrusion_Error err =
5361 MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5362 LLPPs.push_back(LPP);
5364 // update startN for search following egde
5365 if ( aN1isOK ) aVprev = aV2;
5370 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5371 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5372 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5373 for(; itPP!=firstList.end(); itPP++) {
5374 fullList.push_back( *itPP );
5376 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5377 fullList.pop_back();
5379 for(; itLLPP!=LLPPs.end(); itLLPP++) {
5380 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5381 itPP = currList.begin();
5382 SMESH_MeshEditor_PathPoint PP2 = currList.front();
5383 gp_Dir D1 = PP1.Tangent();
5384 gp_Dir D2 = PP2.Tangent();
5385 gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5386 PP1.SetTangent(Dnew);
5387 fullList.push_back(PP1);
5389 for(; itPP!=currList.end(); itPP++) {
5390 fullList.push_back( *itPP );
5392 PP1 = fullList.back();
5393 fullList.pop_back();
5395 // if wire not closed
5396 fullList.push_back(PP1);
5400 return EXTR_BAD_PATH_SHAPE;
5403 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5404 theHasRefPoint, theRefPoint, theMakeGroups);
5408 //=======================================================================
5409 //function : MakeEdgePathPoints
5410 //purpose : auxilary for ExtrusionAlongTrack
5411 //=======================================================================
5412 SMESH_MeshEditor::Extrusion_Error
5413 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5414 const TopoDS_Edge& aTrackEdge,
5416 list<SMESH_MeshEditor_PathPoint>& LPP)
5418 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5420 aTolVec2=aTolVec*aTolVec;
5422 TopoDS_Vertex aV1, aV2;
5423 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5424 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5425 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5426 // 2. Collect parameters on the track edge
5427 aPrms.push_front( aT1 );
5428 aPrms.push_back( aT2 );
5431 if( FirstIsStart ) {
5442 SMESH_MeshEditor_PathPoint aPP;
5443 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5444 std::list<double>::iterator aItD = aPrms.begin();
5445 for(; aItD != aPrms.end(); ++aItD) {
5449 aC3D->D1( aT, aP3D, aVec );
5450 aL2 = aVec.SquareMagnitude();
5451 if ( aL2 < aTolVec2 )
5452 return EXTR_CANT_GET_TANGENT;
5453 gp_Dir aTgt( aVec );
5455 aPP.SetTangent( aTgt );
5456 aPP.SetParameter( aT );
5463 //=======================================================================
5464 //function : MakeExtrElements
5465 //purpose : auxilary for ExtrusionAlongTrack
5466 //=======================================================================
5467 SMESH_MeshEditor::Extrusion_Error
5468 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5469 list<SMESH_MeshEditor_PathPoint>& fullList,
5470 const bool theHasAngles,
5471 list<double>& theAngles,
5472 const bool theLinearVariation,
5473 const bool theHasRefPoint,
5474 const gp_Pnt& theRefPoint,
5475 const bool theMakeGroups)
5477 MESSAGE("MakeExtrElements");
5478 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5479 int aNbTP = fullList.size();
5480 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5482 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5483 LinearAngleVariation(aNbTP-1, theAngles);
5485 vector<double> aAngles( aNbTP );
5487 for(; j<aNbTP; ++j) {
5490 if ( theHasAngles ) {
5492 std::list<double>::iterator aItD = theAngles.begin();
5493 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5495 aAngles[j] = anAngle;
5498 // fill vector of path points with angles
5499 //aPPs.resize(fullList.size());
5501 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5502 for(; itPP!=fullList.end(); itPP++) {
5504 SMESH_MeshEditor_PathPoint PP = *itPP;
5505 PP.SetAngle(aAngles[j]);
5509 TNodeOfNodeListMap mapNewNodes;
5510 TElemOfVecOfNnlmiMap mapElemNewNodes;
5511 TElemOfElemListMap newElemsMap;
5512 TIDSortedElemSet::iterator itElem;
5515 SMDSAbs_ElementType aTypeE;
5516 // source elements for each generated one
5517 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5519 // 3. Center of rotation aV0
5520 gp_Pnt aV0 = theRefPoint;
5522 if ( !theHasRefPoint ) {
5524 aGC.SetCoord( 0.,0.,0. );
5526 itElem = theElements.begin();
5527 for ( ; itElem != theElements.end(); itElem++ ) {
5528 const SMDS_MeshElement* elem = *itElem;
5530 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5531 while ( itN->more() ) {
5532 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5537 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5538 list<const SMDS_MeshNode*> aLNx;
5539 mapNewNodes[node] = aLNx;
5541 gp_XYZ aXYZ( aX, aY, aZ );
5549 } // if (!theHasRefPoint) {
5550 mapNewNodes.clear();
5552 // 4. Processing the elements
5553 SMESHDS_Mesh* aMesh = GetMeshDS();
5555 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5556 // check element type
5557 const SMDS_MeshElement* elem = *itElem;
5558 aTypeE = elem->GetType();
5559 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5562 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5563 newNodesItVec.reserve( elem->NbNodes() );
5565 // loop on elem nodes
5567 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5568 while ( itN->more() )
5571 // check if a node has been already processed
5572 const SMDS_MeshNode* node =
5573 static_cast<const SMDS_MeshNode*>( itN->next() );
5574 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5575 if ( nIt == mapNewNodes.end() ) {
5576 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5577 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5580 aX = node->X(); aY = node->Y(); aZ = node->Z();
5582 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5583 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5584 gp_Ax1 anAx1, anAxT1T0;
5585 gp_Dir aDT1x, aDT0x, aDT1T0;
5590 aPN0.SetCoord(aX, aY, aZ);
5592 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5594 aDT0x= aPP0.Tangent();
5595 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5597 for ( j = 1; j < aNbTP; ++j ) {
5598 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5600 aDT1x = aPP1.Tangent();
5601 aAngle1x = aPP1.Angle();
5603 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5605 gp_Vec aV01x( aP0x, aP1x );
5606 aTrsf.SetTranslation( aV01x );
5609 aV1x = aV0x.Transformed( aTrsf );
5610 aPN1 = aPN0.Transformed( aTrsf );
5612 // rotation 1 [ T1,T0 ]
5613 aAngleT1T0=-aDT1x.Angle( aDT0x );
5614 if (fabs(aAngleT1T0) > aTolAng) {
5616 anAxT1T0.SetLocation( aV1x );
5617 anAxT1T0.SetDirection( aDT1T0 );
5618 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5620 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5624 if ( theHasAngles ) {
5625 anAx1.SetLocation( aV1x );
5626 anAx1.SetDirection( aDT1x );
5627 aTrsfRot.SetRotation( anAx1, aAngle1x );
5629 aPN1 = aPN1.Transformed( aTrsfRot );
5633 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5634 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5635 // create additional node
5636 double x = ( aPN1.X() + aPN0.X() )/2.;
5637 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5638 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5639 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5640 myLastCreatedNodes.Append(newNode);
5641 srcNodes.Append( node );
5642 listNewNodes.push_back( newNode );
5647 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5648 myLastCreatedNodes.Append(newNode);
5649 srcNodes.Append( node );
5650 listNewNodes.push_back( newNode );
5660 // if current elem is quadratic and current node is not medium
5661 // we have to check - may be it is needed to insert additional nodes
5662 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5663 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5664 if(listNewNodes.size()==aNbTP-1) {
5665 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5666 gp_XYZ P(node->X(), node->Y(), node->Z());
5667 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5669 for(i=0; i<aNbTP-1; i++) {
5670 const SMDS_MeshNode* N = *it;
5671 double x = ( N->X() + P.X() )/2.;
5672 double y = ( N->Y() + P.Y() )/2.;
5673 double z = ( N->Z() + P.Z() )/2.;
5674 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5675 srcNodes.Append( node );
5676 myLastCreatedNodes.Append(newN);
5679 P = gp_XYZ(N->X(),N->Y(),N->Z());
5681 listNewNodes.clear();
5682 for(i=0; i<2*(aNbTP-1); i++) {
5683 listNewNodes.push_back(aNodes[i]);
5689 newNodesItVec.push_back( nIt );
5691 // make new elements
5692 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5693 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5694 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5697 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5699 if ( theMakeGroups )
5700 generateGroups( srcNodes, srcElems, "extruded");
5706 //=======================================================================
5707 //function : LinearAngleVariation
5708 //purpose : auxilary for ExtrusionAlongTrack
5709 //=======================================================================
5710 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5711 list<double>& Angles)
5713 int nbAngles = Angles.size();
5714 if( nbSteps > nbAngles ) {
5715 vector<double> theAngles(nbAngles);
5716 list<double>::iterator it = Angles.begin();
5718 for(; it!=Angles.end(); it++) {
5720 theAngles[i] = (*it);
5723 double rAn2St = double( nbAngles ) / double( nbSteps );
5724 double angPrev = 0, angle;
5725 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5726 double angCur = rAn2St * ( iSt+1 );
5727 double angCurFloor = floor( angCur );
5728 double angPrevFloor = floor( angPrev );
5729 if ( angPrevFloor == angCurFloor )
5730 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5732 int iP = int( angPrevFloor );
5733 double angPrevCeil = ceil(angPrev);
5734 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5736 int iC = int( angCurFloor );
5737 if ( iC < nbAngles )
5738 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5740 iP = int( angPrevCeil );
5742 angle += theAngles[ iC ];
5744 res.push_back(angle);
5749 for(; it!=res.end(); it++)
5750 Angles.push_back( *it );
5755 //================================================================================
5757 * \brief Move or copy theElements applying theTrsf to their nodes
5758 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5759 * \param theTrsf - transformation to apply
5760 * \param theCopy - if true, create translated copies of theElems
5761 * \param theMakeGroups - if true and theCopy, create translated groups
5762 * \param theTargetMesh - mesh to copy translated elements into
5763 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5765 //================================================================================
5767 SMESH_MeshEditor::PGroupIDs
5768 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5769 const gp_Trsf& theTrsf,
5771 const bool theMakeGroups,
5772 SMESH_Mesh* theTargetMesh)
5774 myLastCreatedElems.Clear();
5775 myLastCreatedNodes.Clear();
5777 bool needReverse = false;
5778 string groupPostfix;
5779 switch ( theTrsf.Form() ) {
5781 MESSAGE("gp_PntMirror");
5783 groupPostfix = "mirrored";
5786 MESSAGE("gp_Ax1Mirror");
5787 groupPostfix = "mirrored";
5790 MESSAGE("gp_Ax2Mirror");
5792 groupPostfix = "mirrored";
5795 MESSAGE("gp_Rotation");
5796 groupPostfix = "rotated";
5798 case gp_Translation:
5799 MESSAGE("gp_Translation");
5800 groupPostfix = "translated";
5803 MESSAGE("gp_Scale");
5804 groupPostfix = "scaled";
5806 case gp_CompoundTrsf: // different scale by axis
5807 MESSAGE("gp_CompoundTrsf");
5808 groupPostfix = "scaled";
5812 needReverse = false;
5813 groupPostfix = "transformed";
5816 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5817 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5818 SMESHDS_Mesh* aMesh = GetMeshDS();
5821 // map old node to new one
5822 TNodeNodeMap nodeMap;
5824 // elements sharing moved nodes; those of them which have all
5825 // nodes mirrored but are not in theElems are to be reversed
5826 TIDSortedElemSet inverseElemSet;
5828 // source elements for each generated one
5829 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5831 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5832 TIDSortedElemSet orphanNode;
5834 if ( theElems.empty() ) // transform the whole mesh
5837 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5838 while ( eIt->more() ) theElems.insert( eIt->next() );
5840 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5841 while ( nIt->more() )
5843 const SMDS_MeshNode* node = nIt->next();
5844 if ( node->NbInverseElements() == 0)
5845 orphanNode.insert( node );
5849 // loop on elements to transform nodes : first orphan nodes then elems
5850 TIDSortedElemSet::iterator itElem;
5851 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5852 for (int i=0; i<2; i++)
5853 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5854 const SMDS_MeshElement* elem = *itElem;
5858 // loop on elem nodes
5859 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5860 while ( itN->more() ) {
5862 const SMDS_MeshNode* node = cast2Node( itN->next() );
5863 // check if a node has been already transformed
5864 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5865 nodeMap.insert( make_pair ( node, node ));
5866 if ( !n2n_isnew.second )
5870 coord[0] = node->X();
5871 coord[1] = node->Y();
5872 coord[2] = node->Z();
5873 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5874 if ( theTargetMesh ) {
5875 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5876 n2n_isnew.first->second = newNode;
5877 myLastCreatedNodes.Append(newNode);
5878 srcNodes.Append( node );
5880 else if ( theCopy ) {
5881 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5882 n2n_isnew.first->second = newNode;
5883 myLastCreatedNodes.Append(newNode);
5884 srcNodes.Append( node );
5887 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5888 // node position on shape becomes invalid
5889 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5890 ( SMDS_SpacePosition::originSpacePosition() );
5893 // keep inverse elements
5894 if ( !theCopy && !theTargetMesh && needReverse ) {
5895 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5896 while ( invElemIt->more() ) {
5897 const SMDS_MeshElement* iel = invElemIt->next();
5898 inverseElemSet.insert( iel );
5904 // either create new elements or reverse mirrored ones
5905 if ( !theCopy && !needReverse && !theTargetMesh )
5908 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5909 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5910 theElems.insert( *invElemIt );
5912 // Replicate or reverse elements
5914 std::vector<int> iForw;
5915 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5917 const SMDS_MeshElement* elem = *itElem;
5918 if ( !elem ) continue;
5920 SMDSAbs_GeometryType geomType = elem->GetGeomType();
5921 int nbNodes = elem->NbNodes();
5922 if ( geomType == SMDSGeom_NONE ) continue; // node
5924 switch ( geomType ) {
5926 case SMDSGeom_POLYGON: // ---------------------- polygon
5928 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5930 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5931 while (itN->more()) {
5932 const SMDS_MeshNode* node =
5933 static_cast<const SMDS_MeshNode*>(itN->next());
5934 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5935 if (nodeMapIt == nodeMap.end())
5936 break; // not all nodes transformed
5938 // reverse mirrored faces and volumes
5939 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5941 poly_nodes[iNode] = (*nodeMapIt).second;
5945 if ( iNode != nbNodes )
5946 continue; // not all nodes transformed
5948 if ( theTargetMesh ) {
5949 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5950 srcElems.Append( elem );
5952 else if ( theCopy ) {
5953 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5954 srcElems.Append( elem );
5957 aMesh->ChangePolygonNodes(elem, poly_nodes);
5962 case SMDSGeom_POLYHEDRA: // ------------------ polyhedral volume
5964 const SMDS_VtkVolume* aPolyedre =
5965 dynamic_cast<const SMDS_VtkVolume*>( elem );
5967 MESSAGE("Warning: bad volumic element");
5971 vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5972 vector<int> quantities; quantities.reserve( nbNodes );
5974 bool allTransformed = true;
5975 int nbFaces = aPolyedre->NbFaces();
5976 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5977 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5978 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5979 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5980 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5981 if (nodeMapIt == nodeMap.end()) {
5982 allTransformed = false; // not all nodes transformed
5984 poly_nodes.push_back((*nodeMapIt).second);
5986 if ( needReverse && allTransformed )
5987 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5989 quantities.push_back(nbFaceNodes);
5991 if ( !allTransformed )
5992 continue; // not all nodes transformed
5994 if ( theTargetMesh ) {
5995 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5996 srcElems.Append( elem );
5998 else if ( theCopy ) {
5999 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
6000 srcElems.Append( elem );
6003 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6008 case SMDSGeom_BALL: // -------------------- Ball
6010 if ( !theCopy && !theTargetMesh ) continue;
6012 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
6013 if (nodeMapIt == nodeMap.end())
6014 continue; // not all nodes transformed
6016 double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
6017 if ( theTargetMesh ) {
6018 myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
6019 srcElems.Append( elem );
6022 myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
6023 srcElems.Append( elem );
6028 default: // ----------------------- Regular elements
6030 while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
6031 const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
6032 const std::vector<int>& i = needReverse ? iRev : iForw;
6034 // find transformed nodes
6035 vector<const SMDS_MeshNode*> nodes(nbNodes);
6037 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6038 while ( itN->more() ) {
6039 const SMDS_MeshNode* node =
6040 static_cast<const SMDS_MeshNode*>( itN->next() );
6041 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6042 if ( nodeMapIt == nodeMap.end() )
6043 break; // not all nodes transformed
6044 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6046 if ( iNode != nbNodes )
6047 continue; // not all nodes transformed
6049 if ( theTargetMesh ) {
6050 if ( SMDS_MeshElement* copy =
6051 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6052 myLastCreatedElems.Append( copy );
6053 srcElems.Append( elem );
6056 else if ( theCopy ) {
6057 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
6058 srcElems.Append( elem );
6061 // reverse element as it was reversed by transformation
6063 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6065 } // switch ( geomType )
6067 } // loop on elements
6069 PGroupIDs newGroupIDs;
6071 if ( ( theMakeGroups && theCopy ) ||
6072 ( theMakeGroups && theTargetMesh ) )
6073 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
6078 //=======================================================================
6080 * \brief Create groups of elements made during transformation
6081 * \param nodeGens - nodes making corresponding myLastCreatedNodes
6082 * \param elemGens - elements making corresponding myLastCreatedElems
6083 * \param postfix - to append to names of new groups
6085 //=======================================================================
6087 SMESH_MeshEditor::PGroupIDs
6088 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6089 const SMESH_SequenceOfElemPtr& elemGens,
6090 const std::string& postfix,
6091 SMESH_Mesh* targetMesh)
6093 PGroupIDs newGroupIDs( new list<int> );
6094 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6096 // Sort existing groups by types and collect their names
6098 // to store an old group and a generated new ones
6100 using boost::make_tuple;
6101 typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
6102 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6103 vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6105 set< string > groupNames;
6107 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6108 if ( !groupIt->more() ) return newGroupIDs;
6110 int newGroupID = mesh->GetGroupIds().back()+1;
6111 while ( groupIt->more() )
6113 SMESH_Group * group = groupIt->next();
6114 if ( !group ) continue;
6115 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6116 if ( !groupDS || groupDS->IsEmpty() ) continue;
6117 groupNames.insert ( group->GetName() );
6118 groupDS->SetStoreName( group->GetName() );
6119 const SMDSAbs_ElementType type = groupDS->GetType();
6120 SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6121 SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6122 groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
6123 orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
6126 // Loop on nodes and elements to add them in new groups
6128 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6130 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6131 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6132 if ( gens.Length() != elems.Length() )
6133 throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
6135 // loop on created elements
6136 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6138 const SMDS_MeshElement* sourceElem = gens( iElem );
6139 if ( !sourceElem ) {
6140 MESSAGE("generateGroups(): NULL source element");
6143 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6144 if ( groupsOldNew.empty() ) { // no groups of this type at all
6145 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6146 ++iElem; // skip all elements made by sourceElem
6149 // collect all elements made by the iElem-th sourceElem
6150 list< const SMDS_MeshElement* > resultElems;
6151 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6152 if ( resElem != sourceElem )
6153 resultElems.push_back( resElem );
6154 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6155 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6156 if ( resElem != sourceElem )
6157 resultElems.push_back( resElem );
6159 // there must be a top element
6160 const SMDS_MeshElement* topElem = 0;
6163 topElem = resultElems.back();
6164 resultElems.pop_back();
6168 list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6169 for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6170 if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6172 topElem = *resElemIt;
6173 resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt
6178 // add resultElems to groups originted from ones the sourceElem belongs to
6179 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6180 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6182 SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6183 if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6185 // fill in a new group
6186 SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6187 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6188 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6189 newGroup.Add( *resElemIt );
6191 // fill a "top" group
6194 SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6195 newTopGroup.Add( topElem );
6199 } // loop on created elements
6200 }// loop on nodes and elements
6202 // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6204 list<int> topGrouIds;
6205 for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6207 SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>();
6208 SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6209 orderedOldNewGroups[i]->get<2>() };
6210 const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
6211 for ( int is2nd = 0; is2nd < 2; ++is2nd )
6213 SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6214 if ( newGroupDS->IsEmpty() )
6216 mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6221 newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6224 const bool isTop = ( nbNewGroups == 2 &&
6225 newGroupDS->GetType() == oldGroupDS->GetType() &&
6228 string name = oldGroupDS->GetStoreName();
6229 if ( !targetMesh ) {
6230 string suffix = ( isTop ? "top": postfix.c_str() );
6234 while ( !groupNames.insert( name ).second ) // name exists
6235 name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6240 newGroupDS->SetStoreName( name.c_str() );
6242 // make a SMESH_Groups
6243 mesh->AddGroup( newGroupDS );
6245 topGrouIds.push_back( newGroupDS->GetID() );
6247 newGroupIDs->push_back( newGroupDS->GetID() );
6251 newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6256 //================================================================================
6258 * \brief Return list of group of nodes close to each other within theTolerance
6259 * Search among theNodes or in the whole mesh if theNodes is empty using
6260 * an Octree algorithm
6262 //================================================================================
6264 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6265 const double theTolerance,
6266 TListOfListOfNodes & theGroupsOfNodes)
6268 myLastCreatedElems.Clear();
6269 myLastCreatedNodes.Clear();
6271 if ( theNodes.empty() )
6272 { // get all nodes in the mesh
6273 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6274 while ( nIt->more() )
6275 theNodes.insert( theNodes.end(),nIt->next());
6278 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6281 //=======================================================================
6282 //function : SimplifyFace
6284 //=======================================================================
6286 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
6287 vector<const SMDS_MeshNode *>& poly_nodes,
6288 vector<int>& quantities) const
6290 int nbNodes = faceNodes.size();
6295 set<const SMDS_MeshNode*> nodeSet;
6297 // get simple seq of nodes
6298 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6299 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6300 int iSimple = 0, nbUnique = 0;
6302 simpleNodes[iSimple++] = faceNodes[0];
6304 for (int iCur = 1; iCur < nbNodes; iCur++) {
6305 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6306 simpleNodes[iSimple++] = faceNodes[iCur];
6307 if (nodeSet.insert( faceNodes[iCur] ).second)
6311 int nbSimple = iSimple;
6312 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6322 bool foundLoop = (nbSimple > nbUnique);
6325 set<const SMDS_MeshNode*> loopSet;
6326 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6327 const SMDS_MeshNode* n = simpleNodes[iSimple];
6328 if (!loopSet.insert( n ).second) {
6332 int iC = 0, curLast = iSimple;
6333 for (; iC < curLast; iC++) {
6334 if (simpleNodes[iC] == n) break;
6336 int loopLen = curLast - iC;
6338 // create sub-element
6340 quantities.push_back(loopLen);
6341 for (; iC < curLast; iC++) {
6342 poly_nodes.push_back(simpleNodes[iC]);
6345 // shift the rest nodes (place from the first loop position)
6346 for (iC = curLast + 1; iC < nbSimple; iC++) {
6347 simpleNodes[iC - loopLen] = simpleNodes[iC];
6349 nbSimple -= loopLen;
6352 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6353 } // while (foundLoop)
6357 quantities.push_back(iSimple);
6358 for (int i = 0; i < iSimple; i++)
6359 poly_nodes.push_back(simpleNodes[i]);
6365 //=======================================================================
6366 //function : MergeNodes
6367 //purpose : In each group, the cdr of nodes are substituted by the first one
6369 //=======================================================================
6371 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6373 MESSAGE("MergeNodes");
6374 myLastCreatedElems.Clear();
6375 myLastCreatedNodes.Clear();
6377 SMESHDS_Mesh* aMesh = GetMeshDS();
6379 TNodeNodeMap nodeNodeMap; // node to replace - new node
6380 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6381 list< int > rmElemIds, rmNodeIds;
6383 // Fill nodeNodeMap and elems
6385 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6386 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6387 list<const SMDS_MeshNode*>& nodes = *grIt;
6388 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6389 const SMDS_MeshNode* nToKeep = *nIt;
6390 //MESSAGE("node to keep " << nToKeep->GetID());
6391 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6392 const SMDS_MeshNode* nToRemove = *nIt;
6393 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6394 if ( nToRemove != nToKeep ) {
6395 //MESSAGE(" node to remove " << nToRemove->GetID());
6396 rmNodeIds.push_back( nToRemove->GetID() );
6397 AddToSameGroups( nToKeep, nToRemove, aMesh );
6398 // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
6399 // after MergeNodes() w/o creating node in place of merged ones.
6400 const SMDS_PositionPtr& pos = nToRemove->GetPosition();
6401 if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
6402 if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
6403 sm->SetIsAlwaysComputed( true );
6406 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6407 while ( invElemIt->more() ) {
6408 const SMDS_MeshElement* elem = invElemIt->next();
6413 // Change element nodes or remove an element
6415 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6416 for ( ; eIt != elems.end(); eIt++ ) {
6417 const SMDS_MeshElement* elem = *eIt;
6418 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
6419 int nbNodes = elem->NbNodes();
6420 int aShapeId = FindShape( elem );
6422 set<const SMDS_MeshNode*> nodeSet;
6423 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6424 int iUnique = 0, iCur = 0, nbRepl = 0;
6425 vector<int> iRepl( nbNodes );
6427 // get new seq of nodes
6428 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6429 while ( itN->more() ) {
6430 const SMDS_MeshNode* n =
6431 static_cast<const SMDS_MeshNode*>( itN->next() );
6433 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6434 if ( nnIt != nodeNodeMap.end() ) { // n sticks
6436 // BUG 0020185: begin
6438 bool stopRecur = false;
6439 set<const SMDS_MeshNode*> nodesRecur;
6440 nodesRecur.insert(n);
6441 while (!stopRecur) {
6442 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6443 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6444 n = (*nnIt_i).second;
6445 if (!nodesRecur.insert(n).second) {
6446 // error: recursive dependancy
6456 curNodes[ iCur ] = n;
6457 bool isUnique = nodeSet.insert( n ).second;
6459 uniqueNodes[ iUnique++ ] = n;
6461 iRepl[ nbRepl++ ] = iCur;
6465 // Analyse element topology after replacement
6468 int nbUniqueNodes = nodeSet.size();
6469 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
6470 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6471 // Polygons and Polyhedral volumes
6472 if (elem->IsPoly()) {
6474 if (elem->GetType() == SMDSAbs_Face) {
6476 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6478 for (; inode < nbNodes; inode++) {
6479 face_nodes[inode] = curNodes[inode];
6482 vector<const SMDS_MeshNode *> polygons_nodes;
6483 vector<int> quantities;
6484 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6487 for (int iface = 0; iface < nbNew; iface++) {
6488 int nbNodes = quantities[iface];
6489 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6490 for (int ii = 0; ii < nbNodes; ii++, inode++) {
6491 poly_nodes[ii] = polygons_nodes[inode];
6493 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6494 myLastCreatedElems.Append(newElem);
6496 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6499 MESSAGE("ChangeElementNodes MergeNodes Polygon");
6500 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6501 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
6503 if (nbNew > 0) quid = nbNew - 1;
6504 vector<int> newquant(quantities.begin()+quid, quantities.end());
6505 const SMDS_MeshElement* newElem = 0;
6506 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
6507 myLastCreatedElems.Append(newElem);
6508 if ( aShapeId && newElem )
6509 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6510 rmElemIds.push_back(elem->GetID());
6513 rmElemIds.push_back(elem->GetID());
6517 else if (elem->GetType() == SMDSAbs_Volume) {
6518 // Polyhedral volume
6519 if (nbUniqueNodes < 4) {
6520 rmElemIds.push_back(elem->GetID());
6523 // each face has to be analyzed in order to check volume validity
6524 const SMDS_VtkVolume* aPolyedre =
6525 dynamic_cast<const SMDS_VtkVolume*>( elem );
6527 int nbFaces = aPolyedre->NbFaces();
6529 vector<const SMDS_MeshNode *> poly_nodes;
6530 vector<int> quantities;
6532 for (int iface = 1; iface <= nbFaces; iface++) {
6533 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6534 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6536 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6537 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6538 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6539 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6540 faceNode = (*nnIt).second;
6542 faceNodes[inode - 1] = faceNode;
6545 SimplifyFace(faceNodes, poly_nodes, quantities);
6548 if (quantities.size() > 3) {
6549 // to be done: remove coincident faces
6552 if (quantities.size() > 3)
6554 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
6555 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6556 const SMDS_MeshElement* newElem = 0;
6557 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6558 myLastCreatedElems.Append(newElem);
6559 if ( aShapeId && newElem )
6560 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6561 rmElemIds.push_back(elem->GetID());
6565 rmElemIds.push_back(elem->GetID());
6576 // TODO not all the possible cases are solved. Find something more generic?
6577 switch ( nbNodes ) {
6578 case 2: ///////////////////////////////////// EDGE
6579 isOk = false; break;
6580 case 3: ///////////////////////////////////// TRIANGLE
6581 isOk = false; break;
6583 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6585 else { //////////////////////////////////// QUADRANGLE
6586 if ( nbUniqueNodes < 3 )
6588 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6589 isOk = false; // opposite nodes stick
6590 //MESSAGE("isOk " << isOk);
6593 case 6: ///////////////////////////////////// PENTAHEDRON
6594 if ( nbUniqueNodes == 4 ) {
6595 // ---------------------------------> tetrahedron
6597 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6598 // all top nodes stick: reverse a bottom
6599 uniqueNodes[ 0 ] = curNodes [ 1 ];
6600 uniqueNodes[ 1 ] = curNodes [ 0 ];
6602 else if (nbRepl == 3 &&
6603 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6604 // all bottom nodes stick: set a top before
6605 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6606 uniqueNodes[ 0 ] = curNodes [ 3 ];
6607 uniqueNodes[ 1 ] = curNodes [ 4 ];
6608 uniqueNodes[ 2 ] = curNodes [ 5 ];
6610 else if (nbRepl == 4 &&
6611 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6612 // a lateral face turns into a line: reverse a bottom
6613 uniqueNodes[ 0 ] = curNodes [ 1 ];
6614 uniqueNodes[ 1 ] = curNodes [ 0 ];
6619 else if ( nbUniqueNodes == 5 ) {
6620 // PENTAHEDRON --------------------> 2 tetrahedrons
6621 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6622 // a bottom node sticks with a linked top one
6624 SMDS_MeshElement* newElem =
6625 aMesh->AddVolume(curNodes[ 3 ],
6628 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6629 myLastCreatedElems.Append(newElem);
6631 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6632 // 2. : reverse a bottom
6633 uniqueNodes[ 0 ] = curNodes [ 1 ];
6634 uniqueNodes[ 1 ] = curNodes [ 0 ];
6644 if(elem->IsQuadratic()) { // Quadratic quadrangle
6656 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
6659 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
6661 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6662 uniqueNodes[0] = curNodes[0];
6663 uniqueNodes[1] = curNodes[2];
6664 uniqueNodes[2] = curNodes[3];
6665 uniqueNodes[3] = curNodes[5];
6666 uniqueNodes[4] = curNodes[6];
6667 uniqueNodes[5] = curNodes[7];
6670 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6671 uniqueNodes[0] = curNodes[0];
6672 uniqueNodes[1] = curNodes[1];
6673 uniqueNodes[2] = curNodes[2];
6674 uniqueNodes[3] = curNodes[4];
6675 uniqueNodes[4] = curNodes[5];
6676 uniqueNodes[5] = curNodes[6];
6679 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6680 uniqueNodes[0] = curNodes[1];
6681 uniqueNodes[1] = curNodes[2];
6682 uniqueNodes[2] = curNodes[3];
6683 uniqueNodes[3] = curNodes[5];
6684 uniqueNodes[4] = curNodes[6];
6685 uniqueNodes[5] = curNodes[0];
6688 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6689 uniqueNodes[0] = curNodes[0];
6690 uniqueNodes[1] = curNodes[1];
6691 uniqueNodes[2] = curNodes[3];
6692 uniqueNodes[3] = curNodes[4];
6693 uniqueNodes[4] = curNodes[6];
6694 uniqueNodes[5] = curNodes[7];
6697 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6698 uniqueNodes[0] = curNodes[0];
6699 uniqueNodes[1] = curNodes[2];
6700 uniqueNodes[2] = curNodes[3];
6701 uniqueNodes[3] = curNodes[1];
6702 uniqueNodes[4] = curNodes[6];
6703 uniqueNodes[5] = curNodes[7];
6706 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6707 uniqueNodes[0] = curNodes[0];
6708 uniqueNodes[1] = curNodes[1];
6709 uniqueNodes[2] = curNodes[2];
6710 uniqueNodes[3] = curNodes[4];
6711 uniqueNodes[4] = curNodes[5];
6712 uniqueNodes[5] = curNodes[7];
6715 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6716 uniqueNodes[0] = curNodes[0];
6717 uniqueNodes[1] = curNodes[1];
6718 uniqueNodes[2] = curNodes[3];
6719 uniqueNodes[3] = curNodes[4];
6720 uniqueNodes[4] = curNodes[2];
6721 uniqueNodes[5] = curNodes[7];
6724 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6725 uniqueNodes[0] = curNodes[0];
6726 uniqueNodes[1] = curNodes[1];
6727 uniqueNodes[2] = curNodes[2];
6728 uniqueNodes[3] = curNodes[4];
6729 uniqueNodes[4] = curNodes[5];
6730 uniqueNodes[5] = curNodes[3];
6735 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
6738 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
6742 //////////////////////////////////// HEXAHEDRON
6744 SMDS_VolumeTool hexa (elem);
6745 hexa.SetExternalNormal();
6746 if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
6747 //////////////////////// HEX ---> 1 tetrahedron
6748 for ( int iFace = 0; iFace < 6; iFace++ ) {
6749 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6750 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6751 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6752 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6753 // one face turns into a point ...
6754 int iOppFace = hexa.GetOppFaceIndex( iFace );
6755 ind = hexa.GetFaceNodesIndices( iOppFace );
6757 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6758 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6761 if ( nbStick == 1 ) {
6762 // ... and the opposite one - into a triangle.
6764 ind = hexa.GetFaceNodesIndices( iFace );
6765 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6772 else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
6773 //////////////////////// HEX ---> 1 prism
6774 int nbTria = 0, iTria[3];
6775 const int *ind; // indices of face nodes
6776 // look for triangular faces
6777 for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
6778 ind = hexa.GetFaceNodesIndices( iFace );
6779 TIDSortedNodeSet faceNodes;
6780 for ( iCur = 0; iCur < 4; iCur++ )
6781 faceNodes.insert( curNodes[ind[iCur]] );
6782 if ( faceNodes.size() == 3 )
6783 iTria[ nbTria++ ] = iFace;
6785 // check if triangles are opposite
6786 if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
6789 // set nodes of the bottom triangle
6790 ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
6792 for ( iCur = 0; iCur < 4; iCur++ )
6793 if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
6794 indB.push_back( ind[iCur] );
6795 if ( !hexa.IsForward() )
6796 std::swap( indB[0], indB[2] );
6797 for ( iCur = 0; iCur < 3; iCur++ )
6798 uniqueNodes[ iCur ] = curNodes[indB[iCur]];
6799 // set nodes of the top triangle
6800 const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
6801 for ( iCur = 0; iCur < 3; ++iCur )
6802 for ( int j = 0; j < 4; ++j )
6803 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
6805 uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
6811 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6812 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6813 for ( int iFace = 0; iFace < 6; iFace++ ) {
6814 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6815 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6816 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6817 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6818 // one face turns into a point ...
6819 int iOppFace = hexa.GetOppFaceIndex( iFace );
6820 ind = hexa.GetFaceNodesIndices( iOppFace );
6822 iUnique = 2; // reverse a tetrahedron 1 bottom
6823 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6824 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6826 else if ( iUnique >= 0 )
6827 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6829 if ( nbStick == 0 ) {
6830 // ... and the opposite one is a quadrangle
6832 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6833 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6836 SMDS_MeshElement* newElem =
6837 aMesh->AddVolume(curNodes[ind[ 0 ]],
6840 curNodes[indTop[ 0 ]]);
6841 myLastCreatedElems.Append(newElem);
6843 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6850 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6851 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6852 // find indices of quad and tri faces
6853 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6854 for ( iFace = 0; iFace < 6; iFace++ ) {
6855 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6857 for ( iCur = 0; iCur < 4; iCur++ )
6858 nodeSet.insert( curNodes[ind[ iCur ]] );
6859 nbUniqueNodes = nodeSet.size();
6860 if ( nbUniqueNodes == 3 )
6861 iTriFace[ nbTri++ ] = iFace;
6862 else if ( nbUniqueNodes == 4 )
6863 iQuadFace[ nbQuad++ ] = iFace;
6865 if (nbQuad == 2 && nbTri == 4 &&
6866 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6867 // 2 opposite quadrangles stuck with a diagonal;
6868 // sample groups of merged indices: (0-4)(2-6)
6869 // --------------------------------------------> 2 tetrahedrons
6870 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6871 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6872 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6873 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6874 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6875 // stuck with 0-2 diagonal
6883 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6884 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6885 // stuck with 1-3 diagonal
6897 uniqueNodes[ 0 ] = curNodes [ i0 ];
6898 uniqueNodes[ 1 ] = curNodes [ i1d ];
6899 uniqueNodes[ 2 ] = curNodes [ i3d ];
6900 uniqueNodes[ 3 ] = curNodes [ i0t ];
6903 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6907 myLastCreatedElems.Append(newElem);
6909 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6912 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6913 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6914 // --------------------------------------------> prism
6915 // find 2 opposite triangles
6917 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6918 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6919 // find indices of kept and replaced nodes
6920 // and fill unique nodes of 2 opposite triangles
6921 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6922 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6923 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6924 // fill unique nodes
6927 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6928 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
6929 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6931 // iCur of a linked node of the opposite face (make normals co-directed):
6932 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6933 // check that correspondent corners of triangles are linked
6934 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6937 uniqueNodes[ iUnique ] = n;
6938 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6947 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6950 MESSAGE("MergeNodes() removes hexahedron "<< elem);
6957 } // switch ( nbNodes )
6959 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6961 if ( isOk ) { // the elem remains valid after sticking nodes
6962 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
6964 // Change nodes of polyedre
6965 const SMDS_VtkVolume* aPolyedre =
6966 dynamic_cast<const SMDS_VtkVolume*>( elem );
6968 int nbFaces = aPolyedre->NbFaces();
6970 vector<const SMDS_MeshNode *> poly_nodes;
6971 vector<int> quantities (nbFaces);
6973 for (int iface = 1; iface <= nbFaces; iface++) {
6974 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6975 quantities[iface - 1] = nbFaceNodes;
6977 for (inode = 1; inode <= nbFaceNodes; inode++) {
6978 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6980 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6981 if (nnIt != nodeNodeMap.end()) { // curNode sticks
6982 curNode = (*nnIt).second;
6984 poly_nodes.push_back(curNode);
6987 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6990 else // replace non-polyhedron elements
6992 const SMDSAbs_ElementType etyp = elem->GetType();
6993 const int elemId = elem->GetID();
6994 const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
6995 uniqueNodes.resize(nbUniqueNodes);
6997 SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
6999 aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7000 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7001 if ( sm && newElem )
7002 sm->AddElement( newElem );
7003 if ( elem != newElem )
7004 ReplaceElemInGroups( elem, newElem, aMesh );
7008 // Remove invalid regular element or invalid polygon
7009 rmElemIds.push_back( elem->GetID() );
7012 } // loop on elements
7014 // Remove bad elements, then equal nodes (order important)
7016 Remove( rmElemIds, false );
7017 Remove( rmNodeIds, true );
7022 // ========================================================
7023 // class : SortableElement
7024 // purpose : allow sorting elements basing on their nodes
7025 // ========================================================
7026 class SortableElement : public set <const SMDS_MeshElement*>
7030 SortableElement( const SMDS_MeshElement* theElem )
7033 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7034 while ( nodeIt->more() )
7035 this->insert( nodeIt->next() );
7038 const SMDS_MeshElement* Get() const
7041 void Set(const SMDS_MeshElement* e) const
7046 mutable const SMDS_MeshElement* myElem;
7049 //=======================================================================
7050 //function : FindEqualElements
7051 //purpose : Return list of group of elements built on the same nodes.
7052 // Search among theElements or in the whole mesh if theElements is empty
7053 //=======================================================================
7055 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements,
7056 TListOfListOfElementsID & theGroupsOfElementsID)
7058 myLastCreatedElems.Clear();
7059 myLastCreatedNodes.Clear();
7061 typedef map< SortableElement, int > TMapOfNodeSet;
7062 typedef list<int> TGroupOfElems;
7064 if ( theElements.empty() )
7065 { // get all elements in the mesh
7066 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7067 while ( eIt->more() )
7068 theElements.insert( theElements.end(), eIt->next());
7071 vector< TGroupOfElems > arrayOfGroups;
7072 TGroupOfElems groupOfElems;
7073 TMapOfNodeSet mapOfNodeSet;
7075 TIDSortedElemSet::iterator elemIt = theElements.begin();
7076 for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
7077 const SMDS_MeshElement* curElem = *elemIt;
7078 SortableElement SE(curElem);
7081 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7082 if( !(pp.second) ) {
7083 TMapOfNodeSet::iterator& itSE = pp.first;
7084 ind = (*itSE).second;
7085 arrayOfGroups[ind].push_back(curElem->GetID());
7088 groupOfElems.clear();
7089 groupOfElems.push_back(curElem->GetID());
7090 arrayOfGroups.push_back(groupOfElems);
7095 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7096 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7097 groupOfElems = *groupIt;
7098 if ( groupOfElems.size() > 1 ) {
7099 groupOfElems.sort();
7100 theGroupsOfElementsID.push_back(groupOfElems);
7105 //=======================================================================
7106 //function : MergeElements
7107 //purpose : In each given group, substitute all elements by the first one.
7108 //=======================================================================
7110 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7112 myLastCreatedElems.Clear();
7113 myLastCreatedNodes.Clear();
7115 typedef list<int> TListOfIDs;
7116 TListOfIDs rmElemIds; // IDs of elems to remove
7118 SMESHDS_Mesh* aMesh = GetMeshDS();
7120 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7121 while ( groupsIt != theGroupsOfElementsID.end() ) {
7122 TListOfIDs& aGroupOfElemID = *groupsIt;
7123 aGroupOfElemID.sort();
7124 int elemIDToKeep = aGroupOfElemID.front();
7125 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7126 aGroupOfElemID.pop_front();
7127 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7128 while ( idIt != aGroupOfElemID.end() ) {
7129 int elemIDToRemove = *idIt;
7130 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7131 // add the kept element in groups of removed one (PAL15188)
7132 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7133 rmElemIds.push_back( elemIDToRemove );
7139 Remove( rmElemIds, false );
7142 //=======================================================================
7143 //function : MergeEqualElements
7144 //purpose : Remove all but one of elements built on the same nodes.
7145 //=======================================================================
7147 void SMESH_MeshEditor::MergeEqualElements()
7149 TIDSortedElemSet aMeshElements; /* empty input ==
7150 to merge equal elements in the whole mesh */
7151 TListOfListOfElementsID aGroupsOfElementsID;
7152 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7153 MergeElements(aGroupsOfElementsID);
7156 //=======================================================================
7157 //function : findAdjacentFace
7159 //=======================================================================
7161 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7162 const SMDS_MeshNode* n2,
7163 const SMDS_MeshElement* elem)
7165 TIDSortedElemSet elemSet, avoidSet;
7167 avoidSet.insert ( elem );
7168 return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
7171 //=======================================================================
7172 //function : FindFreeBorder
7174 //=======================================================================
7176 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7178 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7179 const SMDS_MeshNode* theSecondNode,
7180 const SMDS_MeshNode* theLastNode,
7181 list< const SMDS_MeshNode* > & theNodes,
7182 list< const SMDS_MeshElement* >& theFaces)
7184 if ( !theFirstNode || !theSecondNode )
7186 // find border face between theFirstNode and theSecondNode
7187 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7191 theFaces.push_back( curElem );
7192 theNodes.push_back( theFirstNode );
7193 theNodes.push_back( theSecondNode );
7195 //vector<const SMDS_MeshNode*> nodes;
7196 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7197 TIDSortedElemSet foundElems;
7198 bool needTheLast = ( theLastNode != 0 );
7200 while ( nStart != theLastNode ) {
7201 if ( nStart == theFirstNode )
7202 return !needTheLast;
7204 // find all free border faces sharing form nStart
7206 list< const SMDS_MeshElement* > curElemList;
7207 list< const SMDS_MeshNode* > nStartList;
7208 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7209 while ( invElemIt->more() ) {
7210 const SMDS_MeshElement* e = invElemIt->next();
7211 if ( e == curElem || foundElems.insert( e ).second ) {
7213 int iNode = 0, nbNodes = e->NbNodes();
7214 //const SMDS_MeshNode* nodes[nbNodes+1];
7215 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7217 if(e->IsQuadratic()) {
7218 const SMDS_VtkFace* F =
7219 dynamic_cast<const SMDS_VtkFace*>(e);
7220 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7221 // use special nodes iterator
7222 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7223 while( anIter->more() ) {
7224 nodes[ iNode++ ] = cast2Node(anIter->next());
7228 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7229 while ( nIt->more() )
7230 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7232 nodes[ iNode ] = nodes[ 0 ];
7234 for ( iNode = 0; iNode < nbNodes; iNode++ )
7235 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7236 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7237 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7239 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7240 curElemList.push_back( e );
7244 // analyse the found
7246 int nbNewBorders = curElemList.size();
7247 if ( nbNewBorders == 0 ) {
7248 // no free border furthermore
7249 return !needTheLast;
7251 else if ( nbNewBorders == 1 ) {
7252 // one more element found
7254 nStart = nStartList.front();
7255 curElem = curElemList.front();
7256 theFaces.push_back( curElem );
7257 theNodes.push_back( nStart );
7260 // several continuations found
7261 list< const SMDS_MeshElement* >::iterator curElemIt;
7262 list< const SMDS_MeshNode* >::iterator nStartIt;
7263 // check if one of them reached the last node
7264 if ( needTheLast ) {
7265 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7266 curElemIt!= curElemList.end();
7267 curElemIt++, nStartIt++ )
7268 if ( *nStartIt == theLastNode ) {
7269 theFaces.push_back( *curElemIt );
7270 theNodes.push_back( *nStartIt );
7274 // find the best free border by the continuations
7275 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7276 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7277 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7278 curElemIt!= curElemList.end();
7279 curElemIt++, nStartIt++ )
7281 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7282 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7283 // find one more free border
7284 if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7288 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7289 // choice: clear a worse one
7290 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7291 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7292 contNodes[ iWorse ].clear();
7293 contFaces[ iWorse ].clear();
7296 if ( contNodes[0].empty() && contNodes[1].empty() )
7299 // append the best free border
7300 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7301 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7302 theNodes.pop_back(); // remove nIgnore
7303 theNodes.pop_back(); // remove nStart
7304 theFaces.pop_back(); // remove curElem
7305 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7306 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7307 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7308 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7311 } // several continuations found
7312 } // while ( nStart != theLastNode )
7317 //=======================================================================
7318 //function : CheckFreeBorderNodes
7319 //purpose : Return true if the tree nodes are on a free border
7320 //=======================================================================
7322 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7323 const SMDS_MeshNode* theNode2,
7324 const SMDS_MeshNode* theNode3)
7326 list< const SMDS_MeshNode* > nodes;
7327 list< const SMDS_MeshElement* > faces;
7328 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7331 //=======================================================================
7332 //function : SewFreeBorder
7334 //=======================================================================
7336 SMESH_MeshEditor::Sew_Error
7337 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7338 const SMDS_MeshNode* theBordSecondNode,
7339 const SMDS_MeshNode* theBordLastNode,
7340 const SMDS_MeshNode* theSideFirstNode,
7341 const SMDS_MeshNode* theSideSecondNode,
7342 const SMDS_MeshNode* theSideThirdNode,
7343 const bool theSideIsFreeBorder,
7344 const bool toCreatePolygons,
7345 const bool toCreatePolyedrs)
7347 myLastCreatedElems.Clear();
7348 myLastCreatedNodes.Clear();
7350 MESSAGE("::SewFreeBorder()");
7351 Sew_Error aResult = SEW_OK;
7353 // ====================================
7354 // find side nodes and elements
7355 // ====================================
7357 list< const SMDS_MeshNode* > nSide[ 2 ];
7358 list< const SMDS_MeshElement* > eSide[ 2 ];
7359 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7360 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7364 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7365 nSide[0], eSide[0])) {
7366 MESSAGE(" Free Border 1 not found " );
7367 aResult = SEW_BORDER1_NOT_FOUND;
7369 if (theSideIsFreeBorder) {
7372 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7373 nSide[1], eSide[1])) {
7374 MESSAGE(" Free Border 2 not found " );
7375 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7378 if ( aResult != SEW_OK )
7381 if (!theSideIsFreeBorder) {
7385 // -------------------------------------------------------------------------
7387 // 1. If nodes to merge are not coincident, move nodes of the free border
7388 // from the coord sys defined by the direction from the first to last
7389 // nodes of the border to the correspondent sys of the side 2
7390 // 2. On the side 2, find the links most co-directed with the correspondent
7391 // links of the free border
7392 // -------------------------------------------------------------------------
7394 // 1. Since sewing may break if there are volumes to split on the side 2,
7395 // we wont move nodes but just compute new coordinates for them
7396 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7397 TNodeXYZMap nBordXYZ;
7398 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7399 list< const SMDS_MeshNode* >::iterator nBordIt;
7401 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7402 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7403 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7404 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7405 double tol2 = 1.e-8;
7406 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7407 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7408 // Need node movement.
7410 // find X and Z axes to create trsf
7411 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7413 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7415 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7418 gp_Ax3 toBordAx( Pb1, Zb, X );
7419 gp_Ax3 fromSideAx( Ps1, Zs, X );
7420 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7422 gp_Trsf toBordSys, fromSide2Sys;
7423 toBordSys.SetTransformation( toBordAx );
7424 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7425 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7428 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7429 const SMDS_MeshNode* n = *nBordIt;
7430 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7431 toBordSys.Transforms( xyz );
7432 fromSide2Sys.Transforms( xyz );
7433 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7437 // just insert nodes XYZ in the nBordXYZ map
7438 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7439 const SMDS_MeshNode* n = *nBordIt;
7440 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7444 // 2. On the side 2, find the links most co-directed with the correspondent
7445 // links of the free border
7447 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7448 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7449 sideNodes.push_back( theSideFirstNode );
7451 bool hasVolumes = false;
7452 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7453 set<long> foundSideLinkIDs, checkedLinkIDs;
7454 SMDS_VolumeTool volume;
7455 //const SMDS_MeshNode* faceNodes[ 4 ];
7457 const SMDS_MeshNode* sideNode;
7458 const SMDS_MeshElement* sideElem;
7459 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7460 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7461 nBordIt = bordNodes.begin();
7463 // border node position and border link direction to compare with
7464 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7465 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7466 // choose next side node by link direction or by closeness to
7467 // the current border node:
7468 bool searchByDir = ( *nBordIt != theBordLastNode );
7470 // find the next node on the Side 2
7472 double maxDot = -DBL_MAX, minDist = DBL_MAX;
7474 checkedLinkIDs.clear();
7475 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7477 // loop on inverse elements of current node (prevSideNode) on the Side 2
7478 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7479 while ( invElemIt->more() )
7481 const SMDS_MeshElement* elem = invElemIt->next();
7482 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7483 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7484 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7485 bool isVolume = volume.Set( elem );
7486 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7487 if ( isVolume ) // --volume
7489 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7490 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7491 if(elem->IsQuadratic()) {
7492 const SMDS_VtkFace* F =
7493 dynamic_cast<const SMDS_VtkFace*>(elem);
7494 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7495 // use special nodes iterator
7496 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7497 while( anIter->more() ) {
7498 nodes[ iNode ] = cast2Node(anIter->next());
7499 if ( nodes[ iNode++ ] == prevSideNode )
7500 iPrevNode = iNode - 1;
7504 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7505 while ( nIt->more() ) {
7506 nodes[ iNode ] = cast2Node( nIt->next() );
7507 if ( nodes[ iNode++ ] == prevSideNode )
7508 iPrevNode = iNode - 1;
7511 // there are 2 links to check
7516 // loop on links, to be precise, on the second node of links
7517 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7518 const SMDS_MeshNode* n = nodes[ iNode ];
7520 if ( !volume.IsLinked( n, prevSideNode ))
7524 if ( iNode ) // a node before prevSideNode
7525 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7526 else // a node after prevSideNode
7527 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7529 // check if this link was already used
7530 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7531 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7532 if (!isJustChecked &&
7533 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7535 // test a link geometrically
7536 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7537 bool linkIsBetter = false;
7538 double dot = 0.0, dist = 0.0;
7539 if ( searchByDir ) { // choose most co-directed link
7540 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7541 linkIsBetter = ( dot > maxDot );
7543 else { // choose link with the node closest to bordPos
7544 dist = ( nextXYZ - bordPos ).SquareModulus();
7545 linkIsBetter = ( dist < minDist );
7547 if ( linkIsBetter ) {
7556 } // loop on inverse elements of prevSideNode
7559 MESSAGE(" Cant find path by links of the Side 2 ");
7560 return SEW_BAD_SIDE_NODES;
7562 sideNodes.push_back( sideNode );
7563 sideElems.push_back( sideElem );
7564 foundSideLinkIDs.insert ( linkID );
7565 prevSideNode = sideNode;
7567 if ( *nBordIt == theBordLastNode )
7568 searchByDir = false;
7570 // find the next border link to compare with
7571 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7572 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7573 // move to next border node if sideNode is before forward border node (bordPos)
7574 while ( *nBordIt != theBordLastNode && !searchByDir ) {
7575 prevBordNode = *nBordIt;
7577 bordPos = nBordXYZ[ *nBordIt ];
7578 bordDir = bordPos - nBordXYZ[ prevBordNode ];
7579 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7583 while ( sideNode != theSideSecondNode );
7585 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7586 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7587 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7589 } // end nodes search on the side 2
7591 // ============================
7592 // sew the border to the side 2
7593 // ============================
7595 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
7596 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7598 TListOfListOfNodes nodeGroupsToMerge;
7599 if ( nbNodes[0] == nbNodes[1] ||
7600 ( theSideIsFreeBorder && !theSideThirdNode)) {
7602 // all nodes are to be merged
7604 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7605 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7606 nIt[0]++, nIt[1]++ )
7608 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7609 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7610 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7615 // insert new nodes into the border and the side to get equal nb of segments
7617 // get normalized parameters of nodes on the borders
7618 //double param[ 2 ][ maxNbNodes ];
7620 param[0] = new double [ maxNbNodes ];
7621 param[1] = new double [ maxNbNodes ];
7623 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7624 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7625 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7626 const SMDS_MeshNode* nPrev = *nIt;
7627 double bordLength = 0;
7628 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7629 const SMDS_MeshNode* nCur = *nIt;
7630 gp_XYZ segment (nCur->X() - nPrev->X(),
7631 nCur->Y() - nPrev->Y(),
7632 nCur->Z() - nPrev->Z());
7633 double segmentLen = segment.Modulus();
7634 bordLength += segmentLen;
7635 param[ iBord ][ iNode ] = bordLength;
7638 // normalize within [0,1]
7639 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7640 param[ iBord ][ iNode ] /= bordLength;
7644 // loop on border segments
7645 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7646 int i[ 2 ] = { 0, 0 };
7647 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7648 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7650 TElemOfNodeListMap insertMap;
7651 TElemOfNodeListMap::iterator insertMapIt;
7653 // key: elem to insert nodes into
7654 // value: 2 nodes to insert between + nodes to be inserted
7656 bool next[ 2 ] = { false, false };
7658 // find min adjacent segment length after sewing
7659 double nextParam = 10., prevParam = 0;
7660 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7661 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7662 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7663 if ( i[ iBord ] > 0 )
7664 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7666 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7667 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7668 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7670 // choose to insert or to merge nodes
7671 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7672 if ( Abs( du ) <= minSegLen * 0.2 ) {
7675 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7676 const SMDS_MeshNode* n0 = *nIt[0];
7677 const SMDS_MeshNode* n1 = *nIt[1];
7678 nodeGroupsToMerge.back().push_back( n1 );
7679 nodeGroupsToMerge.back().push_back( n0 );
7680 // position of node of the border changes due to merge
7681 param[ 0 ][ i[0] ] += du;
7682 // move n1 for the sake of elem shape evaluation during insertion.
7683 // n1 will be removed by MergeNodes() anyway
7684 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7685 next[0] = next[1] = true;
7690 int intoBord = ( du < 0 ) ? 0 : 1;
7691 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7692 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7693 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7694 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7695 if ( intoBord == 1 ) {
7696 // move node of the border to be on a link of elem of the side
7697 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7698 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7699 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7700 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7701 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7703 insertMapIt = insertMap.find( elem );
7704 bool notFound = ( insertMapIt == insertMap.end() );
7705 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7707 // insert into another link of the same element:
7708 // 1. perform insertion into the other link of the elem
7709 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7710 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7711 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7712 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7713 // 2. perform insertion into the link of adjacent faces
7715 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7717 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7721 if (toCreatePolyedrs) {
7722 // perform insertion into the links of adjacent volumes
7723 UpdateVolumes(n12, n22, nodeList);
7725 // 3. find an element appeared on n1 and n2 after the insertion
7726 insertMap.erase( elem );
7727 elem = findAdjacentFace( n1, n2, 0 );
7729 if ( notFound || otherLink ) {
7730 // add element and nodes of the side into the insertMap
7731 insertMapIt = insertMap.insert
7732 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7733 (*insertMapIt).second.push_back( n1 );
7734 (*insertMapIt).second.push_back( n2 );
7736 // add node to be inserted into elem
7737 (*insertMapIt).second.push_back( nIns );
7738 next[ 1 - intoBord ] = true;
7741 // go to the next segment
7742 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7743 if ( next[ iBord ] ) {
7744 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7746 nPrev[ iBord ] = *nIt[ iBord ];
7747 nIt[ iBord ]++; i[ iBord ]++;
7751 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7753 // perform insertion of nodes into elements
7755 for (insertMapIt = insertMap.begin();
7756 insertMapIt != insertMap.end();
7759 const SMDS_MeshElement* elem = (*insertMapIt).first;
7760 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7761 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7762 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7764 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7766 if ( !theSideIsFreeBorder ) {
7767 // look for and insert nodes into the faces adjacent to elem
7769 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7771 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7776 if (toCreatePolyedrs) {
7777 // perform insertion into the links of adjacent volumes
7778 UpdateVolumes(n1, n2, nodeList);
7784 } // end: insert new nodes
7786 MergeNodes ( nodeGroupsToMerge );
7791 //=======================================================================
7792 //function : InsertNodesIntoLink
7793 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7794 // and theBetweenNode2 and split theElement
7795 //=======================================================================
7797 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7798 const SMDS_MeshNode* theBetweenNode1,
7799 const SMDS_MeshNode* theBetweenNode2,
7800 list<const SMDS_MeshNode*>& theNodesToInsert,
7801 const bool toCreatePoly)
7803 if ( theFace->GetType() != SMDSAbs_Face ) return;
7805 // find indices of 2 link nodes and of the rest nodes
7806 int iNode = 0, il1, il2, i3, i4;
7807 il1 = il2 = i3 = i4 = -1;
7808 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7809 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7811 if(theFace->IsQuadratic()) {
7812 const SMDS_VtkFace* F =
7813 dynamic_cast<const SMDS_VtkFace*>(theFace);
7814 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7815 // use special nodes iterator
7816 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7817 while( anIter->more() ) {
7818 const SMDS_MeshNode* n = cast2Node(anIter->next());
7819 if ( n == theBetweenNode1 )
7821 else if ( n == theBetweenNode2 )
7827 nodes[ iNode++ ] = n;
7831 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7832 while ( nodeIt->more() ) {
7833 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7834 if ( n == theBetweenNode1 )
7836 else if ( n == theBetweenNode2 )
7842 nodes[ iNode++ ] = n;
7845 if ( il1 < 0 || il2 < 0 || i3 < 0 )
7848 // arrange link nodes to go one after another regarding the face orientation
7849 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7850 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7855 aNodesToInsert.reverse();
7857 // check that not link nodes of a quadrangles are in good order
7858 int nbFaceNodes = theFace->NbNodes();
7859 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7865 if (toCreatePoly || theFace->IsPoly()) {
7868 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7870 // add nodes of face up to first node of link
7873 if(theFace->IsQuadratic()) {
7874 const SMDS_VtkFace* F =
7875 dynamic_cast<const SMDS_VtkFace*>(theFace);
7876 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7877 // use special nodes iterator
7878 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7879 while( anIter->more() && !isFLN ) {
7880 const SMDS_MeshNode* n = cast2Node(anIter->next());
7881 poly_nodes[iNode++] = n;
7882 if (n == nodes[il1]) {
7886 // add nodes to insert
7887 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7888 for (; nIt != aNodesToInsert.end(); nIt++) {
7889 poly_nodes[iNode++] = *nIt;
7891 // add nodes of face starting from last node of link
7892 while ( anIter->more() ) {
7893 poly_nodes[iNode++] = cast2Node(anIter->next());
7897 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7898 while ( nodeIt->more() && !isFLN ) {
7899 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7900 poly_nodes[iNode++] = n;
7901 if (n == nodes[il1]) {
7905 // add nodes to insert
7906 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7907 for (; nIt != aNodesToInsert.end(); nIt++) {
7908 poly_nodes[iNode++] = *nIt;
7910 // add nodes of face starting from last node of link
7911 while ( nodeIt->more() ) {
7912 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7913 poly_nodes[iNode++] = n;
7917 // edit or replace the face
7918 SMESHDS_Mesh *aMesh = GetMeshDS();
7920 if (theFace->IsPoly()) {
7921 aMesh->ChangePolygonNodes(theFace, poly_nodes);
7924 int aShapeId = FindShape( theFace );
7926 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7927 myLastCreatedElems.Append(newElem);
7928 if ( aShapeId && newElem )
7929 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7931 aMesh->RemoveElement(theFace);
7936 SMESHDS_Mesh *aMesh = GetMeshDS();
7937 if( !theFace->IsQuadratic() ) {
7939 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7940 int nbLinkNodes = 2 + aNodesToInsert.size();
7941 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7942 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7943 linkNodes[ 0 ] = nodes[ il1 ];
7944 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7945 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7946 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7947 linkNodes[ iNode++ ] = *nIt;
7949 // decide how to split a quadrangle: compare possible variants
7950 // and choose which of splits to be a quadrangle
7951 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7952 if ( nbFaceNodes == 3 ) {
7953 iBestQuad = nbSplits;
7956 else if ( nbFaceNodes == 4 ) {
7957 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7958 double aBestRate = DBL_MAX;
7959 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7961 double aBadRate = 0;
7962 // evaluate elements quality
7963 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7964 if ( iSplit == iQuad ) {
7965 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7969 aBadRate += getBadRate( &quad, aCrit );
7972 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7974 nodes[ iSplit < iQuad ? i4 : i3 ]);
7975 aBadRate += getBadRate( &tria, aCrit );
7979 if ( aBadRate < aBestRate ) {
7981 aBestRate = aBadRate;
7986 // create new elements
7987 int aShapeId = FindShape( theFace );
7990 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7991 SMDS_MeshElement* newElem = 0;
7992 if ( iSplit == iBestQuad )
7993 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7998 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8000 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8001 myLastCreatedElems.Append(newElem);
8002 if ( aShapeId && newElem )
8003 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8006 // change nodes of theFace
8007 const SMDS_MeshNode* newNodes[ 4 ];
8008 newNodes[ 0 ] = linkNodes[ i1 ];
8009 newNodes[ 1 ] = linkNodes[ i2 ];
8010 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8011 newNodes[ 3 ] = nodes[ i4 ];
8012 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8013 const SMDS_MeshElement* newElem = 0;
8014 if (iSplit == iBestQuad)
8015 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8017 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8018 myLastCreatedElems.Append(newElem);
8019 if ( aShapeId && newElem )
8020 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8021 } // end if(!theFace->IsQuadratic())
8022 else { // theFace is quadratic
8023 // we have to split theFace on simple triangles and one simple quadrangle
8025 int nbshift = tmp*2;
8026 // shift nodes in nodes[] by nbshift
8028 for(i=0; i<nbshift; i++) {
8029 const SMDS_MeshNode* n = nodes[0];
8030 for(j=0; j<nbFaceNodes-1; j++) {
8031 nodes[j] = nodes[j+1];
8033 nodes[nbFaceNodes-1] = n;
8035 il1 = il1 - nbshift;
8036 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8037 // n0 n1 n2 n0 n1 n2
8038 // +-----+-----+ +-----+-----+
8047 // create new elements
8048 int aShapeId = FindShape( theFace );
8051 if(nbFaceNodes==6) { // quadratic triangle
8052 SMDS_MeshElement* newElem =
8053 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8054 myLastCreatedElems.Append(newElem);
8055 if ( aShapeId && newElem )
8056 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8057 if(theFace->IsMediumNode(nodes[il1])) {
8058 // create quadrangle
8059 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8060 myLastCreatedElems.Append(newElem);
8061 if ( aShapeId && newElem )
8062 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8068 // create quadrangle
8069 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8070 myLastCreatedElems.Append(newElem);
8071 if ( aShapeId && newElem )
8072 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8078 else { // nbFaceNodes==8 - quadratic quadrangle
8079 SMDS_MeshElement* newElem =
8080 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8081 myLastCreatedElems.Append(newElem);
8082 if ( aShapeId && newElem )
8083 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8084 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8085 myLastCreatedElems.Append(newElem);
8086 if ( aShapeId && newElem )
8087 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8088 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8089 myLastCreatedElems.Append(newElem);
8090 if ( aShapeId && newElem )
8091 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8092 if(theFace->IsMediumNode(nodes[il1])) {
8093 // create quadrangle
8094 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8095 myLastCreatedElems.Append(newElem);
8096 if ( aShapeId && newElem )
8097 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8103 // create quadrangle
8104 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8105 myLastCreatedElems.Append(newElem);
8106 if ( aShapeId && newElem )
8107 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8113 // create needed triangles using n1,n2,n3 and inserted nodes
8114 int nbn = 2 + aNodesToInsert.size();
8115 //const SMDS_MeshNode* aNodes[nbn];
8116 vector<const SMDS_MeshNode*> aNodes(nbn);
8117 aNodes[0] = nodes[n1];
8118 aNodes[nbn-1] = nodes[n2];
8119 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8120 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8121 aNodes[iNode++] = *nIt;
8123 for(i=1; i<nbn; i++) {
8124 SMDS_MeshElement* newElem =
8125 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8126 myLastCreatedElems.Append(newElem);
8127 if ( aShapeId && newElem )
8128 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8132 aMesh->RemoveElement(theFace);
8135 //=======================================================================
8136 //function : UpdateVolumes
8138 //=======================================================================
8139 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8140 const SMDS_MeshNode* theBetweenNode2,
8141 list<const SMDS_MeshNode*>& theNodesToInsert)
8143 myLastCreatedElems.Clear();
8144 myLastCreatedNodes.Clear();
8146 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8147 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8148 const SMDS_MeshElement* elem = invElemIt->next();
8150 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8151 SMDS_VolumeTool aVolume (elem);
8152 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8155 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8156 int iface, nbFaces = aVolume.NbFaces();
8157 vector<const SMDS_MeshNode *> poly_nodes;
8158 vector<int> quantities (nbFaces);
8160 for (iface = 0; iface < nbFaces; iface++) {
8161 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8162 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8163 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8165 for (int inode = 0; inode < nbFaceNodes; inode++) {
8166 poly_nodes.push_back(faceNodes[inode]);
8168 if (nbInserted == 0) {
8169 if (faceNodes[inode] == theBetweenNode1) {
8170 if (faceNodes[inode + 1] == theBetweenNode2) {
8171 nbInserted = theNodesToInsert.size();
8173 // add nodes to insert
8174 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8175 for (; nIt != theNodesToInsert.end(); nIt++) {
8176 poly_nodes.push_back(*nIt);
8180 else if (faceNodes[inode] == theBetweenNode2) {
8181 if (faceNodes[inode + 1] == theBetweenNode1) {
8182 nbInserted = theNodesToInsert.size();
8184 // add nodes to insert in reversed order
8185 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8187 for (; nIt != theNodesToInsert.begin(); nIt--) {
8188 poly_nodes.push_back(*nIt);
8190 poly_nodes.push_back(*nIt);
8197 quantities[iface] = nbFaceNodes + nbInserted;
8200 // Replace or update the volume
8201 SMESHDS_Mesh *aMesh = GetMeshDS();
8203 if (elem->IsPoly()) {
8204 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8208 int aShapeId = FindShape( elem );
8210 SMDS_MeshElement* newElem =
8211 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8212 myLastCreatedElems.Append(newElem);
8213 if (aShapeId && newElem)
8214 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8216 aMesh->RemoveElement(elem);
8223 //================================================================================
8225 * \brief Transform any volume into data of SMDSEntity_Polyhedra
8227 //================================================================================
8229 void volumeToPolyhedron( const SMDS_MeshElement* elem,
8230 vector<const SMDS_MeshNode *> & nodes,
8231 vector<int> & nbNodeInFaces )
8234 nbNodeInFaces.clear();
8235 SMDS_VolumeTool vTool ( elem );
8236 for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
8238 const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
8239 nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
8240 nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
8245 //=======================================================================
8247 * \brief Convert elements contained in a submesh to quadratic
8248 * \return int - nb of checked elements
8250 //=======================================================================
8252 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8253 SMESH_MesherHelper& theHelper,
8254 const bool theForce3d)
8257 if( !theSm ) return nbElem;
8259 vector<int> nbNodeInFaces;
8260 vector<const SMDS_MeshNode *> nodes;
8261 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8262 while(ElemItr->more())
8265 const SMDS_MeshElement* elem = ElemItr->next();
8266 if( !elem ) continue;
8268 // analyse a necessity of conversion
8269 const SMDSAbs_ElementType aType = elem->GetType();
8270 if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
8272 const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
8273 bool hasCentralNodes = false;
8274 if ( elem->IsQuadratic() )
8277 switch ( aGeomType ) {
8278 case SMDSEntity_Quad_Triangle:
8279 case SMDSEntity_Quad_Quadrangle:
8280 case SMDSEntity_Quad_Hexa:
8281 alreadyOK = !theHelper.GetIsBiQuadratic(); break;
8283 case SMDSEntity_BiQuad_Triangle:
8284 case SMDSEntity_BiQuad_Quadrangle:
8285 case SMDSEntity_TriQuad_Hexa:
8286 alreadyOK = theHelper.GetIsBiQuadratic();
8287 hasCentralNodes = true;
8292 // take into account already present modium nodes
8294 case SMDSAbs_Volume:
8295 theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
8297 theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
8299 theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
8305 // get elem data needed to re-create it
8307 const int id = elem->GetID();
8308 const int nbNodes = elem->NbCornerNodes();
8309 nodes.assign(elem->begin_nodes(), elem->end_nodes());
8310 if ( aGeomType == SMDSEntity_Polyhedra )
8311 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
8312 else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
8313 volumeToPolyhedron( elem, nodes, nbNodeInFaces );
8315 // remove a linear element
8316 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8318 // remove central nodes of biquadratic elements (biquad->quad convertion)
8319 if ( hasCentralNodes )
8320 for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
8321 if ( nodes[i]->NbInverseElements() == 0 )
8322 GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
8324 const SMDS_MeshElement* NewElem = 0;
8330 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8338 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8341 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8344 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8348 case SMDSAbs_Volume :
8352 case SMDSEntity_Tetra:
8353 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8355 case SMDSEntity_Pyramid:
8356 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8358 case SMDSEntity_Penta:
8359 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8361 case SMDSEntity_Hexa:
8362 case SMDSEntity_Quad_Hexa:
8363 case SMDSEntity_TriQuad_Hexa:
8364 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8365 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8367 case SMDSEntity_Hexagonal_Prism:
8369 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8376 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8377 if( NewElem && NewElem->getshapeId() < 1 )
8378 theSm->AddElement( NewElem );
8382 //=======================================================================
8383 //function : ConvertToQuadratic
8385 //=======================================================================
8387 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
8389 SMESHDS_Mesh* meshDS = GetMeshDS();
8391 SMESH_MesherHelper aHelper(*myMesh);
8393 aHelper.SetIsQuadratic( true );
8394 aHelper.SetIsBiQuadratic( theToBiQuad );
8395 aHelper.SetElementsOnShape(true);
8397 // convert elements assigned to sub-meshes
8398 int nbCheckedElems = 0;
8399 if ( myMesh->HasShapeToMesh() )
8401 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8403 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8404 while ( smIt->more() ) {
8405 SMESH_subMesh* sm = smIt->next();
8406 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8407 aHelper.SetSubShape( sm->GetSubShape() );
8408 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8414 // convert elements NOT assigned to sub-meshes
8415 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8416 if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
8418 aHelper.SetElementsOnShape(false);
8419 SMESHDS_SubMesh *smDS = 0;
8422 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8423 while( aEdgeItr->more() )
8425 const SMDS_MeshEdge* edge = aEdgeItr->next();
8426 if ( !edge->IsQuadratic() )
8428 int id = edge->GetID();
8429 const SMDS_MeshNode* n1 = edge->GetNode(0);
8430 const SMDS_MeshNode* n2 = edge->GetNode(1);
8432 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8434 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8435 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8439 aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
8444 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8445 while( aFaceItr->more() )
8447 const SMDS_MeshFace* face = aFaceItr->next();
8448 if ( !face ) continue;
8450 const SMDSAbs_EntityType type = face->GetEntityType();
8454 case SMDSEntity_Quad_Triangle:
8455 case SMDSEntity_Quad_Quadrangle:
8456 alreadyOK = !theToBiQuad;
8457 aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8459 case SMDSEntity_BiQuad_Triangle:
8460 case SMDSEntity_BiQuad_Quadrangle:
8461 alreadyOK = theToBiQuad;
8462 aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8464 default: alreadyOK = false;
8469 const int id = face->GetID();
8470 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8472 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8474 SMDS_MeshFace * NewFace = 0;
8477 case SMDSEntity_Triangle:
8478 case SMDSEntity_Quad_Triangle:
8479 case SMDSEntity_BiQuad_Triangle:
8480 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8481 if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
8482 GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
8485 case SMDSEntity_Quadrangle:
8486 case SMDSEntity_Quad_Quadrangle:
8487 case SMDSEntity_BiQuad_Quadrangle:
8488 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8489 if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
8490 GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
8494 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8496 ReplaceElemInGroups( face, NewFace, GetMeshDS());
8500 vector<int> nbNodeInFaces;
8501 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8502 while(aVolumeItr->more())
8504 const SMDS_MeshVolume* volume = aVolumeItr->next();
8505 if ( !volume ) continue;
8507 const SMDSAbs_EntityType type = volume->GetEntityType();
8508 if (( theToBiQuad && type == SMDSEntity_TriQuad_Hexa ) ||
8509 ( !theToBiQuad && type == SMDSEntity_Quad_Hexa ))
8511 aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
8514 const int id = volume->GetID();
8515 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8516 if ( type == SMDSEntity_Polyhedra )
8517 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
8518 else if ( type == SMDSEntity_Hexagonal_Prism )
8519 volumeToPolyhedron( volume, nodes, nbNodeInFaces );
8521 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8523 SMDS_MeshVolume * NewVolume = 0;
8526 case SMDSEntity_Tetra:
8527 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
8529 case SMDSEntity_Hexa:
8530 case SMDSEntity_Quad_Hexa:
8531 case SMDSEntity_TriQuad_Hexa:
8532 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8533 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8534 for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
8535 if ( nodes[i]->NbInverseElements() == 0 )
8536 GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
8538 case SMDSEntity_Pyramid:
8539 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8540 nodes[3], nodes[4], id, theForce3d);
8542 case SMDSEntity_Penta:
8543 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8544 nodes[3], nodes[4], nodes[5], id, theForce3d);
8546 case SMDSEntity_Hexagonal_Prism:
8548 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8550 ReplaceElemInGroups(volume, NewVolume, meshDS);
8555 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8556 // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8557 // aHelper.FixQuadraticElements(myError);
8558 SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8562 //================================================================================
8564 * \brief Makes given elements quadratic
8565 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
8566 * \param theElements - elements to make quadratic
8568 //================================================================================
8570 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
8571 TIDSortedElemSet& theElements,
8572 const bool theToBiQuad)
8574 if ( theElements.empty() ) return;
8576 // we believe that all theElements are of the same type
8577 const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
8579 // get all nodes shared by theElements
8580 TIDSortedNodeSet allNodes;
8581 TIDSortedElemSet::iterator eIt = theElements.begin();
8582 for ( ; eIt != theElements.end(); ++eIt )
8583 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
8585 // complete theElements with elements of lower dim whose all nodes are in allNodes
8587 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
8588 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
8589 TIDSortedNodeSet::iterator nIt = allNodes.begin();
8590 for ( ; nIt != allNodes.end(); ++nIt )
8592 const SMDS_MeshNode* n = *nIt;
8593 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
8594 while ( invIt->more() )
8596 const SMDS_MeshElement* e = invIt->next();
8597 const SMDSAbs_ElementType type = e->GetType();
8598 if ( e->IsQuadratic() )
8600 quadAdjacentElems[ type ].insert( e );
8603 switch ( e->GetEntityType() ) {
8604 case SMDSEntity_Quad_Triangle:
8605 case SMDSEntity_Quad_Quadrangle:
8606 case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break;
8607 case SMDSEntity_BiQuad_Triangle:
8608 case SMDSEntity_BiQuad_Quadrangle:
8609 case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
8610 default: alreadyOK = true;
8615 if ( type >= elemType )
8616 continue; // same type or more complex linear element
8618 if ( !checkedAdjacentElems[ type ].insert( e ).second )
8619 continue; // e is already checked
8623 SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
8624 while ( nodeIt->more() && allIn )
8625 allIn = allNodes.count( nodeIt->next() );
8627 theElements.insert(e );
8631 SMESH_MesherHelper helper(*myMesh);
8632 helper.SetIsQuadratic( true );
8633 helper.SetIsBiQuadratic( theToBiQuad );
8635 // add links of quadratic adjacent elements to the helper
8637 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
8638 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
8639 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
8641 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
8643 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
8644 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
8645 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
8647 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
8649 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
8650 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
8651 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
8653 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
8656 // make quadratic (or bi-tri-quadratic) elements instead of linear ones
8658 SMESHDS_Mesh* meshDS = GetMeshDS();
8659 SMESHDS_SubMesh* smDS = 0;
8660 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
8662 const SMDS_MeshElement* elem = *eIt;
8665 int nbCentralNodes = 0;
8666 switch ( elem->GetEntityType() ) {
8667 // linear convertible
8668 case SMDSEntity_Edge:
8669 case SMDSEntity_Triangle:
8670 case SMDSEntity_Quadrangle:
8671 case SMDSEntity_Tetra:
8672 case SMDSEntity_Pyramid:
8673 case SMDSEntity_Hexa:
8674 case SMDSEntity_Penta: alreadyOK = false; nbCentralNodes = 0; break;
8675 // quadratic that can become bi-quadratic
8676 case SMDSEntity_Quad_Triangle:
8677 case SMDSEntity_Quad_Quadrangle:
8678 case SMDSEntity_Quad_Hexa: alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
8680 case SMDSEntity_BiQuad_Triangle:
8681 case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
8682 case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
8684 default: alreadyOK = true;
8686 if ( alreadyOK ) continue;
8688 const SMDSAbs_ElementType type = elem->GetType();
8689 const int id = elem->GetID();
8690 const int nbNodes = elem->NbCornerNodes();
8691 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
8693 helper.SetSubShape( elem->getshapeId() );
8695 if ( !smDS || !smDS->Contains( elem ))
8696 smDS = meshDS->MeshElements( elem->getshapeId() );
8697 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
8699 SMDS_MeshElement * newElem = 0;
8702 case 4: // cases for most frequently used element types go first (for optimization)
8703 if ( type == SMDSAbs_Volume )
8704 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8706 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8709 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8710 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8713 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
8716 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8719 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8720 nodes[4], id, theForce3d);
8723 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8724 nodes[4], nodes[5], id, theForce3d);
8728 ReplaceElemInGroups( elem, newElem, meshDS);
8729 if( newElem && smDS )
8730 smDS->AddElement( newElem );
8732 // remove central nodes
8733 for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
8734 if ( nodes[i]->NbInverseElements() == 0 )
8735 meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
8737 } // loop on theElements
8740 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8741 // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8742 // helper.FixQuadraticElements( myError );
8743 SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8747 //=======================================================================
8749 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8750 * \return int - nb of checked elements
8752 //=======================================================================
8754 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
8755 SMDS_ElemIteratorPtr theItr,
8756 const int theShapeID)
8759 SMESHDS_Mesh* meshDS = GetMeshDS();
8761 while( theItr->more() )
8763 const SMDS_MeshElement* elem = theItr->next();
8765 if( elem && elem->IsQuadratic())
8767 int id = elem->GetID();
8768 int nbCornerNodes = elem->NbCornerNodes();
8769 SMDSAbs_ElementType aType = elem->GetType();
8771 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
8773 //remove a quadratic element
8774 if ( !theSm || !theSm->Contains( elem ))
8775 theSm = meshDS->MeshElements( elem->getshapeId() );
8776 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
8778 // remove medium nodes
8779 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
8780 if ( nodes[i]->NbInverseElements() == 0 )
8781 meshDS->RemoveFreeNode( nodes[i], theSm );
8783 // add a linear element
8784 nodes.resize( nbCornerNodes );
8785 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
8786 ReplaceElemInGroups(elem, newElem, meshDS);
8787 if( theSm && newElem )
8788 theSm->AddElement( newElem );
8794 //=======================================================================
8795 //function : ConvertFromQuadratic
8797 //=======================================================================
8799 bool SMESH_MeshEditor::ConvertFromQuadratic()
8801 int nbCheckedElems = 0;
8802 if ( myMesh->HasShapeToMesh() )
8804 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8806 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8807 while ( smIt->more() ) {
8808 SMESH_subMesh* sm = smIt->next();
8809 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8810 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8816 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8817 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8819 SMESHDS_SubMesh *aSM = 0;
8820 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8828 //================================================================================
8830 * \brief Return true if all medium nodes of the element are in the node set
8832 //================================================================================
8834 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
8836 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
8837 if ( !nodeSet.count( elem->GetNode(i) ))
8843 //================================================================================
8845 * \brief Makes given elements linear
8847 //================================================================================
8849 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
8851 if ( theElements.empty() ) return;
8853 // collect IDs of medium nodes of theElements; some of these nodes will be removed
8854 set<int> mediumNodeIDs;
8855 TIDSortedElemSet::iterator eIt = theElements.begin();
8856 for ( ; eIt != theElements.end(); ++eIt )
8858 const SMDS_MeshElement* e = *eIt;
8859 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
8860 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
8863 // replace given elements by linear ones
8864 SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
8865 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8867 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
8868 // except those elements sharing medium nodes of quadratic element whose medium nodes
8869 // are not all in mediumNodeIDs
8871 // get remaining medium nodes
8872 TIDSortedNodeSet mediumNodes;
8873 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
8874 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
8875 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
8876 mediumNodes.insert( mediumNodes.end(), n );
8878 // find more quadratic elements to convert
8879 TIDSortedElemSet moreElemsToConvert;
8880 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
8881 for ( ; nIt != mediumNodes.end(); ++nIt )
8883 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
8884 while ( invIt->more() )
8886 const SMDS_MeshElement* e = invIt->next();
8887 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
8889 // find a more complex element including e and
8890 // whose medium nodes are not in mediumNodes
8891 bool complexFound = false;
8892 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
8894 SMDS_ElemIteratorPtr invIt2 =
8895 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
8896 while ( invIt2->more() )
8898 const SMDS_MeshElement* eComplex = invIt2->next();
8899 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
8901 int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
8902 if ( nbCommonNodes == e->NbNodes())
8904 complexFound = true;
8905 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
8911 if ( !complexFound )
8912 moreElemsToConvert.insert( e );
8916 elemIt = elemSetIterator( moreElemsToConvert );
8917 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8920 //=======================================================================
8921 //function : SewSideElements
8923 //=======================================================================
8925 SMESH_MeshEditor::Sew_Error
8926 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
8927 TIDSortedElemSet& theSide2,
8928 const SMDS_MeshNode* theFirstNode1,
8929 const SMDS_MeshNode* theFirstNode2,
8930 const SMDS_MeshNode* theSecondNode1,
8931 const SMDS_MeshNode* theSecondNode2)
8933 myLastCreatedElems.Clear();
8934 myLastCreatedNodes.Clear();
8936 MESSAGE ("::::SewSideElements()");
8937 if ( theSide1.size() != theSide2.size() )
8938 return SEW_DIFF_NB_OF_ELEMENTS;
8940 Sew_Error aResult = SEW_OK;
8942 // 1. Build set of faces representing each side
8943 // 2. Find which nodes of the side 1 to merge with ones on the side 2
8944 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8946 // =======================================================================
8947 // 1. Build set of faces representing each side:
8948 // =======================================================================
8949 // a. build set of nodes belonging to faces
8950 // b. complete set of faces: find missing faces whose nodes are in set of nodes
8951 // c. create temporary faces representing side of volumes if correspondent
8952 // face does not exist
8954 SMESHDS_Mesh* aMesh = GetMeshDS();
8955 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
8956 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
8957 TIDSortedElemSet faceSet1, faceSet2;
8958 set<const SMDS_MeshElement*> volSet1, volSet2;
8959 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
8960 TIDSortedElemSet * faceSetPtr[] = { &faceSet1, &faceSet2 };
8961 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
8962 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8963 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8964 int iSide, iFace, iNode;
8966 list<const SMDS_MeshElement* > tempFaceList;
8967 for ( iSide = 0; iSide < 2; iSide++ ) {
8968 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
8969 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8970 TIDSortedElemSet * faceSet = faceSetPtr[ iSide ];
8971 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
8972 set<const SMDS_MeshElement*>::iterator vIt;
8973 TIDSortedElemSet::iterator eIt;
8974 set<const SMDS_MeshNode*>::iterator nIt;
8976 // check that given nodes belong to given elements
8977 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8978 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8979 int firstIndex = -1, secondIndex = -1;
8980 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8981 const SMDS_MeshElement* elem = *eIt;
8982 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
8983 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8984 if ( firstIndex > -1 && secondIndex > -1 ) break;
8986 if ( firstIndex < 0 || secondIndex < 0 ) {
8987 // we can simply return until temporary faces created
8988 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8991 // -----------------------------------------------------------
8992 // 1a. Collect nodes of existing faces
8993 // and build set of face nodes in order to detect missing
8994 // faces corresponding to sides of volumes
8995 // -----------------------------------------------------------
8997 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8999 // loop on the given element of a side
9000 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9001 //const SMDS_MeshElement* elem = *eIt;
9002 const SMDS_MeshElement* elem = *eIt;
9003 if ( elem->GetType() == SMDSAbs_Face ) {
9004 faceSet->insert( elem );
9005 set <const SMDS_MeshNode*> faceNodeSet;
9006 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9007 while ( nodeIt->more() ) {
9008 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9009 nodeSet->insert( n );
9010 faceNodeSet.insert( n );
9012 setOfFaceNodeSet.insert( faceNodeSet );
9014 else if ( elem->GetType() == SMDSAbs_Volume )
9015 volSet->insert( elem );
9017 // ------------------------------------------------------------------------------
9018 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9019 // ------------------------------------------------------------------------------
9021 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9022 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9023 while ( fIt->more() ) { // loop on faces sharing a node
9024 const SMDS_MeshElement* f = fIt->next();
9025 if ( faceSet->find( f ) == faceSet->end() ) {
9026 // check if all nodes are in nodeSet and
9027 // complete setOfFaceNodeSet if they are
9028 set <const SMDS_MeshNode*> faceNodeSet;
9029 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9030 bool allInSet = true;
9031 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9032 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9033 if ( nodeSet->find( n ) == nodeSet->end() )
9036 faceNodeSet.insert( n );
9039 faceSet->insert( f );
9040 setOfFaceNodeSet.insert( faceNodeSet );
9046 // -------------------------------------------------------------------------
9047 // 1c. Create temporary faces representing sides of volumes if correspondent
9048 // face does not exist
9049 // -------------------------------------------------------------------------
9051 if ( !volSet->empty() ) {
9052 //int nodeSetSize = nodeSet->size();
9054 // loop on given volumes
9055 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9056 SMDS_VolumeTool vol (*vIt);
9057 // loop on volume faces: find free faces
9058 // --------------------------------------
9059 list<const SMDS_MeshElement* > freeFaceList;
9060 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9061 if ( !vol.IsFreeFace( iFace ))
9063 // check if there is already a face with same nodes in a face set
9064 const SMDS_MeshElement* aFreeFace = 0;
9065 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9066 int nbNodes = vol.NbFaceNodes( iFace );
9067 set <const SMDS_MeshNode*> faceNodeSet;
9068 vol.GetFaceNodes( iFace, faceNodeSet );
9069 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9071 // no such a face is given but it still can exist, check it
9072 vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
9073 aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
9076 // create a temporary face
9077 if ( nbNodes == 3 ) {
9078 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9079 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9081 else if ( nbNodes == 4 ) {
9082 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9083 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9086 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9087 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9088 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9091 tempFaceList.push_back( aFreeFace );
9095 freeFaceList.push_back( aFreeFace );
9097 } // loop on faces of a volume
9099 // choose one of several free faces of a volume
9100 // --------------------------------------------
9101 if ( freeFaceList.size() > 1 ) {
9102 // choose a face having max nb of nodes shared by other elems of a side
9103 int maxNbNodes = -1;
9104 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9105 while ( fIt != freeFaceList.end() ) { // loop on free faces
9106 int nbSharedNodes = 0;
9107 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9108 while ( nodeIt->more() ) { // loop on free face nodes
9109 const SMDS_MeshNode* n =
9110 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9111 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9112 while ( invElemIt->more() ) {
9113 const SMDS_MeshElement* e = invElemIt->next();
9114 nbSharedNodes += faceSet->count( e );
9115 nbSharedNodes += elemSet->count( e );
9118 if ( nbSharedNodes > maxNbNodes ) {
9119 maxNbNodes = nbSharedNodes;
9120 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9122 else if ( nbSharedNodes == maxNbNodes ) {
9126 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9129 if ( freeFaceList.size() > 1 )
9131 // could not choose one face, use another way
9132 // choose a face most close to the bary center of the opposite side
9133 gp_XYZ aBC( 0., 0., 0. );
9134 set <const SMDS_MeshNode*> addedNodes;
9135 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9136 eIt = elemSet2->begin();
9137 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9138 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9139 while ( nodeIt->more() ) { // loop on free face nodes
9140 const SMDS_MeshNode* n =
9141 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9142 if ( addedNodes.insert( n ).second )
9143 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9146 aBC /= addedNodes.size();
9147 double minDist = DBL_MAX;
9148 fIt = freeFaceList.begin();
9149 while ( fIt != freeFaceList.end() ) { // loop on free faces
9151 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9152 while ( nodeIt->more() ) { // loop on free face nodes
9153 const SMDS_MeshNode* n =
9154 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9155 gp_XYZ p( n->X(),n->Y(),n->Z() );
9156 dist += ( aBC - p ).SquareModulus();
9158 if ( dist < minDist ) {
9160 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9163 fIt = freeFaceList.erase( fIt++ );
9166 } // choose one of several free faces of a volume
9168 if ( freeFaceList.size() == 1 ) {
9169 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9170 faceSet->insert( aFreeFace );
9171 // complete a node set with nodes of a found free face
9172 // for ( iNode = 0; iNode < ; iNode++ )
9173 // nodeSet->insert( fNodes[ iNode ] );
9176 } // loop on volumes of a side
9178 // // complete a set of faces if new nodes in a nodeSet appeared
9179 // // ----------------------------------------------------------
9180 // if ( nodeSetSize != nodeSet->size() ) {
9181 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9182 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9183 // while ( fIt->more() ) { // loop on faces sharing a node
9184 // const SMDS_MeshElement* f = fIt->next();
9185 // if ( faceSet->find( f ) == faceSet->end() ) {
9186 // // check if all nodes are in nodeSet and
9187 // // complete setOfFaceNodeSet if they are
9188 // set <const SMDS_MeshNode*> faceNodeSet;
9189 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9190 // bool allInSet = true;
9191 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9192 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9193 // if ( nodeSet->find( n ) == nodeSet->end() )
9194 // allInSet = false;
9196 // faceNodeSet.insert( n );
9198 // if ( allInSet ) {
9199 // faceSet->insert( f );
9200 // setOfFaceNodeSet.insert( faceNodeSet );
9206 } // Create temporary faces, if there are volumes given
9209 if ( faceSet1.size() != faceSet2.size() ) {
9210 // delete temporary faces: they are in reverseElements of actual nodes
9211 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9212 // while ( tmpFaceIt->more() )
9213 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9214 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9215 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9216 // aMesh->RemoveElement(*tmpFaceIt);
9217 MESSAGE("Diff nb of faces");
9218 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9221 // ============================================================
9222 // 2. Find nodes to merge:
9223 // bind a node to remove to a node to put instead
9224 // ============================================================
9226 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9227 if ( theFirstNode1 != theFirstNode2 )
9228 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9229 if ( theSecondNode1 != theSecondNode2 )
9230 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9232 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9233 set< long > linkIdSet; // links to process
9234 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9236 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9237 list< NLink > linkList[2];
9238 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9239 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9240 // loop on links in linkList; find faces by links and append links
9241 // of the found faces to linkList
9242 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9243 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9245 NLink link[] = { *linkIt[0], *linkIt[1] };
9246 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9247 if ( !linkIdSet.count( linkID ) )
9250 // by links, find faces in the face sets,
9251 // and find indices of link nodes in the found faces;
9252 // in a face set, there is only one or no face sharing a link
9253 // ---------------------------------------------------------------
9255 const SMDS_MeshElement* face[] = { 0, 0 };
9256 vector<const SMDS_MeshNode*> fnodes[2];
9257 int iLinkNode[2][2];
9258 TIDSortedElemSet avoidSet;
9259 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9260 const SMDS_MeshNode* n1 = link[iSide].first;
9261 const SMDS_MeshNode* n2 = link[iSide].second;
9262 //cout << "Side " << iSide << " ";
9263 //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9264 // find a face by two link nodes
9265 face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
9266 *faceSetPtr[ iSide ], avoidSet,
9267 &iLinkNode[iSide][0],
9268 &iLinkNode[iSide][1] );
9271 //cout << " F " << face[ iSide]->GetID() <<endl;
9272 faceSetPtr[ iSide ]->erase( face[ iSide ]);
9273 // put face nodes to fnodes
9274 if ( face[ iSide ]->IsQuadratic() )
9276 // use interlaced nodes iterator
9277 const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
9278 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9279 SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
9280 while ( nIter->more() )
9281 fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
9285 fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
9286 face[ iSide ]->end_nodes() );
9288 fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9292 // check similarity of elements of the sides
9293 if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9294 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9295 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9296 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9299 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9301 break; // do not return because it's necessary to remove tmp faces
9304 // set nodes to merge
9305 // -------------------
9307 if ( face[0] && face[1] ) {
9308 const int nbNodes = face[0]->NbNodes();
9309 if ( nbNodes != face[1]->NbNodes() ) {
9310 MESSAGE("Diff nb of face nodes");
9311 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9312 break; // do not return because it s necessary to remove tmp faces
9314 bool reverse[] = { false, false }; // order of nodes in the link
9315 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9316 // analyse link orientation in faces
9317 int i1 = iLinkNode[ iSide ][ 0 ];
9318 int i2 = iLinkNode[ iSide ][ 1 ];
9319 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9321 int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9322 int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9323 for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9325 nReplaceMap.insert ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9326 fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9329 // add other links of the faces to linkList
9330 // -----------------------------------------
9332 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9333 linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9334 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9335 if ( !iter_isnew.second ) { // already in a set: no need to process
9336 linkIdSet.erase( iter_isnew.first );
9338 else // new in set == encountered for the first time: add
9340 const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9341 const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9342 linkList[0].push_back ( NLink( n1, n2 ));
9343 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9348 if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9351 } // loop on link lists
9353 if ( aResult == SEW_OK &&
9354 ( //linkIt[0] != linkList[0].end() ||
9355 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9356 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9357 " " << (faceSetPtr[1]->empty()));
9358 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9361 // ====================================================================
9362 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9363 // ====================================================================
9365 // delete temporary faces
9366 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9367 // while ( tmpFaceIt->more() )
9368 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9369 list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9370 for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9371 aMesh->RemoveElement(*tmpFaceIt);
9373 if ( aResult != SEW_OK)
9376 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9377 // loop on nodes replacement map
9378 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9379 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9380 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9381 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9382 nodeIDsToRemove.push_back( nToRemove->GetID() );
9383 // loop on elements sharing nToRemove
9384 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9385 while ( invElemIt->more() ) {
9386 const SMDS_MeshElement* e = invElemIt->next();
9387 // get a new suite of nodes: make replacement
9388 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9389 vector< const SMDS_MeshNode*> nodes( nbNodes );
9390 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9391 while ( nIt->more() ) {
9392 const SMDS_MeshNode* n =
9393 static_cast<const SMDS_MeshNode*>( nIt->next() );
9394 nnIt = nReplaceMap.find( n );
9395 if ( nnIt != nReplaceMap.end() ) {
9401 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9402 // elemIDsToRemove.push_back( e->GetID() );
9406 SMDSAbs_ElementType etyp = e->GetType();
9407 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
9410 myLastCreatedElems.Append(newElem);
9411 AddToSameGroups(newElem, e, aMesh);
9412 int aShapeId = e->getshapeId();
9415 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9418 aMesh->RemoveElement(e);
9423 Remove( nodeIDsToRemove, true );
9428 //================================================================================
9430 * \brief Find corresponding nodes in two sets of faces
9431 * \param theSide1 - first face set
9432 * \param theSide2 - second first face
9433 * \param theFirstNode1 - a boundary node of set 1
9434 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9435 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9436 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9437 * \param nReplaceMap - output map of corresponding nodes
9438 * \return bool - is a success or not
9440 //================================================================================
9443 //#define DEBUG_MATCHING_NODES
9446 SMESH_MeshEditor::Sew_Error
9447 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9448 set<const SMDS_MeshElement*>& theSide2,
9449 const SMDS_MeshNode* theFirstNode1,
9450 const SMDS_MeshNode* theFirstNode2,
9451 const SMDS_MeshNode* theSecondNode1,
9452 const SMDS_MeshNode* theSecondNode2,
9453 TNodeNodeMap & nReplaceMap)
9455 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9457 nReplaceMap.clear();
9458 if ( theFirstNode1 != theFirstNode2 )
9459 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9460 if ( theSecondNode1 != theSecondNode2 )
9461 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9463 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9464 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9466 list< NLink > linkList[2];
9467 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9468 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9470 // loop on links in linkList; find faces by links and append links
9471 // of the found faces to linkList
9472 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9473 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9474 NLink link[] = { *linkIt[0], *linkIt[1] };
9475 if ( linkSet.find( link[0] ) == linkSet.end() )
9478 // by links, find faces in the face sets,
9479 // and find indices of link nodes in the found faces;
9480 // in a face set, there is only one or no face sharing a link
9481 // ---------------------------------------------------------------
9483 const SMDS_MeshElement* face[] = { 0, 0 };
9484 list<const SMDS_MeshNode*> notLinkNodes[2];
9485 //bool reverse[] = { false, false }; // order of notLinkNodes
9487 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9489 const SMDS_MeshNode* n1 = link[iSide].first;
9490 const SMDS_MeshNode* n2 = link[iSide].second;
9491 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9492 set< const SMDS_MeshElement* > facesOfNode1;
9493 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9495 // during a loop of the first node, we find all faces around n1,
9496 // during a loop of the second node, we find one face sharing both n1 and n2
9497 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9498 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9499 while ( fIt->more() ) { // loop on faces sharing a node
9500 const SMDS_MeshElement* f = fIt->next();
9501 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9502 ! facesOfNode1.insert( f ).second ) // f encounters twice
9504 if ( face[ iSide ] ) {
9505 MESSAGE( "2 faces per link " );
9506 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9509 faceSet->erase( f );
9511 // get not link nodes
9512 int nbN = f->NbNodes();
9513 if ( f->IsQuadratic() )
9515 nbNodes[ iSide ] = nbN;
9516 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9517 int i1 = f->GetNodeIndex( n1 );
9518 int i2 = f->GetNodeIndex( n2 );
9519 int iEnd = nbN, iBeg = -1, iDelta = 1;
9520 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9522 std::swap( iEnd, iBeg ); iDelta = -1;
9527 if ( i == iEnd ) i = iBeg + iDelta;
9528 if ( i == i1 ) break;
9529 nodes.push_back ( f->GetNode( i ) );
9535 // check similarity of elements of the sides
9536 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9537 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9538 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9539 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9542 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9546 // set nodes to merge
9547 // -------------------
9549 if ( face[0] && face[1] ) {
9550 if ( nbNodes[0] != nbNodes[1] ) {
9551 MESSAGE("Diff nb of face nodes");
9552 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9554 #ifdef DEBUG_MATCHING_NODES
9555 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9556 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9557 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9559 int nbN = nbNodes[0];
9561 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9562 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9563 for ( int i = 0 ; i < nbN - 2; ++i ) {
9564 #ifdef DEBUG_MATCHING_NODES
9565 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9567 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9571 // add other links of the face 1 to linkList
9572 // -----------------------------------------
9574 const SMDS_MeshElement* f0 = face[0];
9575 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9576 for ( int i = 0; i < nbN; i++ )
9578 const SMDS_MeshNode* n2 = f0->GetNode( i );
9579 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9580 linkSet.insert( SMESH_TLink( n1, n2 ));
9581 if ( !iter_isnew.second ) { // already in a set: no need to process
9582 linkSet.erase( iter_isnew.first );
9584 else // new in set == encountered for the first time: add
9586 #ifdef DEBUG_MATCHING_NODES
9587 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9588 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9590 linkList[0].push_back ( NLink( n1, n2 ));
9591 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9596 } // loop on link lists
9601 //================================================================================
9603 * \brief Create elements equal (on same nodes) to given ones
9604 * \param [in] theElements - a set of elems to duplicate. If it is empty, all
9605 * elements of the uppest dimension are duplicated.
9607 //================================================================================
9609 void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
9612 SMESHDS_Mesh* mesh = GetMeshDS();
9614 // get an element type and an iterator over elements
9616 SMDSAbs_ElementType type;
9617 SMDS_ElemIteratorPtr elemIt;
9618 vector< const SMDS_MeshElement* > allElems;
9619 if ( theElements.empty() )
9621 if ( mesh->NbNodes() == 0 )
9623 // get most complex type
9624 SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
9625 SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
9626 SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
9628 for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
9629 if ( mesh->GetMeshInfo().NbElements( types[i] ))
9634 // put all elements in the vector <allElems>
9635 allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
9636 elemIt = mesh->elementsIterator( type );
9637 while ( elemIt->more() )
9638 allElems.push_back( elemIt->next());
9639 elemIt = elemSetIterator( allElems );
9643 type = (*theElements.begin())->GetType();
9644 elemIt = elemSetIterator( theElements );
9647 // duplicate elements
9649 if ( type == SMDSAbs_Ball )
9651 SMDS_UnstructuredGrid* vtkGrid = mesh->getGrid();
9652 while ( elemIt->more() )
9654 const SMDS_MeshElement* elem = elemIt->next();
9655 if ( elem->GetType() != SMDSAbs_Ball )
9657 if (( elem = mesh->AddBall( elem->GetNode(0),
9658 vtkGrid->GetBallDiameter( elem->getVtkId() ))))
9659 myLastCreatedElems.Append( elem );
9664 vector< const SMDS_MeshNode* > nodes;
9665 while ( elemIt->more() )
9667 const SMDS_MeshElement* elem = elemIt->next();
9668 if ( elem->GetType() != type )
9671 nodes.assign( elem->begin_nodes(), elem->end_nodes() );
9673 if ( type == SMDSAbs_Volume && elem->GetVtkType() == VTK_POLYHEDRON )
9675 std::vector<int> quantities =
9676 static_cast< const SMDS_VtkVolume* >( elem )->GetQuantities();
9677 elem = mesh->AddPolyhedralVolume( nodes, quantities );
9681 AddElement( nodes, type, elem->IsPoly() );
9682 elem = 0; // myLastCreatedElems is already filled
9685 myLastCreatedElems.Append( elem );
9690 //================================================================================
9692 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9693 \param theElems - the list of elements (edges or faces) to be replicated
9694 The nodes for duplication could be found from these elements
9695 \param theNodesNot - list of nodes to NOT replicate
9696 \param theAffectedElems - the list of elements (cells and edges) to which the
9697 replicated nodes should be associated to.
9698 \return TRUE if operation has been completed successfully, FALSE otherwise
9700 //================================================================================
9702 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9703 const TIDSortedElemSet& theNodesNot,
9704 const TIDSortedElemSet& theAffectedElems )
9706 myLastCreatedElems.Clear();
9707 myLastCreatedNodes.Clear();
9709 if ( theElems.size() == 0 )
9712 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9717 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9718 // duplicate elements and nodes
9719 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9720 // replce nodes by duplications
9721 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9725 //================================================================================
9727 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9728 \param theMeshDS - mesh instance
9729 \param theElems - the elements replicated or modified (nodes should be changed)
9730 \param theNodesNot - nodes to NOT replicate
9731 \param theNodeNodeMap - relation of old node to new created node
9732 \param theIsDoubleElem - flag os to replicate element or modify
9733 \return TRUE if operation has been completed successfully, FALSE otherwise
9735 //================================================================================
9737 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9738 const TIDSortedElemSet& theElems,
9739 const TIDSortedElemSet& theNodesNot,
9740 std::map< const SMDS_MeshNode*,
9741 const SMDS_MeshNode* >& theNodeNodeMap,
9742 const bool theIsDoubleElem )
9744 MESSAGE("doubleNodes");
9745 // iterate on through element and duplicate them (by nodes duplication)
9747 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9748 for ( ; elemItr != theElems.end(); ++elemItr )
9750 const SMDS_MeshElement* anElem = *elemItr;
9754 bool isDuplicate = false;
9755 // duplicate nodes to duplicate element
9756 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9757 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9759 while ( anIter->more() )
9762 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9763 SMDS_MeshNode* aNewNode = aCurrNode;
9764 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9765 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9766 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9769 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9770 theNodeNodeMap[ aCurrNode ] = aNewNode;
9771 myLastCreatedNodes.Append( aNewNode );
9773 isDuplicate |= (aCurrNode != aNewNode);
9774 newNodes[ ind++ ] = aNewNode;
9779 if ( theIsDoubleElem )
9780 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9783 MESSAGE("ChangeElementNodes");
9784 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9791 //================================================================================
9793 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9794 \param theNodes - identifiers of nodes to be doubled
9795 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9796 nodes. If list of element identifiers is empty then nodes are doubled but
9797 they not assigned to elements
9798 \return TRUE if operation has been completed successfully, FALSE otherwise
9800 //================================================================================
9802 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9803 const std::list< int >& theListOfModifiedElems )
9805 MESSAGE("DoubleNodes");
9806 myLastCreatedElems.Clear();
9807 myLastCreatedNodes.Clear();
9809 if ( theListOfNodes.size() == 0 )
9812 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9816 // iterate through nodes and duplicate them
9818 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9820 std::list< int >::const_iterator aNodeIter;
9821 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9823 int aCurr = *aNodeIter;
9824 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9830 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9833 anOldNodeToNewNode[ aNode ] = aNewNode;
9834 myLastCreatedNodes.Append( aNewNode );
9838 // Create map of new nodes for modified elements
9840 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9842 std::list< int >::const_iterator anElemIter;
9843 for ( anElemIter = theListOfModifiedElems.begin();
9844 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9846 int aCurr = *anElemIter;
9847 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9851 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9853 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9855 while ( anIter->more() )
9857 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9858 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9860 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9861 aNodeArr[ ind++ ] = aNewNode;
9864 aNodeArr[ ind++ ] = aCurrNode;
9866 anElemToNodes[ anElem ] = aNodeArr;
9869 // Change nodes of elements
9871 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9872 anElemToNodesIter = anElemToNodes.begin();
9873 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9875 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9876 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9879 MESSAGE("ChangeElementNodes");
9880 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9889 //================================================================================
9891 \brief Check if element located inside shape
9892 \return TRUE if IN or ON shape, FALSE otherwise
9894 //================================================================================
9896 template<class Classifier>
9897 bool isInside(const SMDS_MeshElement* theElem,
9898 Classifier& theClassifier,
9899 const double theTol)
9901 gp_XYZ centerXYZ (0, 0, 0);
9902 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9903 while (aNodeItr->more())
9904 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
9906 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9907 theClassifier.Perform(aPnt, theTol);
9908 TopAbs_State aState = theClassifier.State();
9909 return (aState == TopAbs_IN || aState == TopAbs_ON );
9912 //================================================================================
9914 * \brief Classifier of the 3D point on the TopoDS_Face
9915 * with interaface suitable for isInside()
9917 //================================================================================
9919 struct _FaceClassifier
9921 Extrema_ExtPS _extremum;
9922 BRepAdaptor_Surface _surface;
9923 TopAbs_State _state;
9925 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9927 _extremum.Initialize( _surface,
9928 _surface.FirstUParameter(), _surface.LastUParameter(),
9929 _surface.FirstVParameter(), _surface.LastVParameter(),
9930 _surface.Tolerance(), _surface.Tolerance() );
9932 void Perform(const gp_Pnt& aPnt, double theTol)
9934 _state = TopAbs_OUT;
9935 _extremum.Perform(aPnt);
9936 if ( _extremum.IsDone() )
9937 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9938 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
9939 _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9941 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9944 TopAbs_State State() const
9951 //================================================================================
9953 \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
9954 This method is the first step of DoubleNodeElemGroupsInRegion.
9955 \param theElems - list of groups of elements (edges or faces) to be replicated
9956 \param theNodesNot - list of groups of nodes not to replicated
9957 \param theShape - shape to detect affected elements (element which geometric center
9958 located on or inside shape).
9959 The replicated nodes should be associated to affected elements.
9960 \return groups of affected elements
9961 \sa DoubleNodeElemGroupsInRegion()
9963 //================================================================================
9965 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
9966 const TIDSortedElemSet& theNodesNot,
9967 const TopoDS_Shape& theShape,
9968 TIDSortedElemSet& theAffectedElems)
9970 if ( theShape.IsNull() )
9973 const double aTol = Precision::Confusion();
9974 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9975 auto_ptr<_FaceClassifier> aFaceClassifier;
9976 if ( theShape.ShapeType() == TopAbs_SOLID )
9978 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9979 bsc3d->PerformInfinitePoint(aTol);
9981 else if (theShape.ShapeType() == TopAbs_FACE )
9983 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9986 // iterates on indicated elements and get elements by back references from their nodes
9987 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9988 for ( ; elemItr != theElems.end(); ++elemItr )
9990 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9994 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9995 while ( nodeItr->more() )
9997 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9998 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10000 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10001 while ( backElemItr->more() )
10003 const SMDS_MeshElement* curElem = backElemItr->next();
10004 if ( curElem && theElems.find(curElem) == theElems.end() &&
10006 isInside( curElem, *bsc3d, aTol ) :
10007 isInside( curElem, *aFaceClassifier, aTol )))
10008 theAffectedElems.insert( curElem );
10015 //================================================================================
10017 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10018 \param theElems - group of of elements (edges or faces) to be replicated
10019 \param theNodesNot - group of nodes not to replicate
10020 \param theShape - shape to detect affected elements (element which geometric center
10021 located on or inside shape).
10022 The replicated nodes should be associated to affected elements.
10023 \return TRUE if operation has been completed successfully, FALSE otherwise
10025 //================================================================================
10027 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10028 const TIDSortedElemSet& theNodesNot,
10029 const TopoDS_Shape& theShape )
10031 if ( theShape.IsNull() )
10034 const double aTol = Precision::Confusion();
10035 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10036 auto_ptr<_FaceClassifier> aFaceClassifier;
10037 if ( theShape.ShapeType() == TopAbs_SOLID )
10039 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10040 bsc3d->PerformInfinitePoint(aTol);
10042 else if (theShape.ShapeType() == TopAbs_FACE )
10044 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10047 // iterates on indicated elements and get elements by back references from their nodes
10048 TIDSortedElemSet anAffected;
10049 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10050 for ( ; elemItr != theElems.end(); ++elemItr )
10052 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10056 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10057 while ( nodeItr->more() )
10059 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10060 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10062 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10063 while ( backElemItr->more() )
10065 const SMDS_MeshElement* curElem = backElemItr->next();
10066 if ( curElem && theElems.find(curElem) == theElems.end() &&
10068 isInside( curElem, *bsc3d, aTol ) :
10069 isInside( curElem, *aFaceClassifier, aTol )))
10070 anAffected.insert( curElem );
10074 return DoubleNodes( theElems, theNodesNot, anAffected );
10078 * \brief compute an oriented angle between two planes defined by four points.
10079 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10080 * @param p0 base of the rotation axe
10081 * @param p1 extremity of the rotation axe
10082 * @param g1 belongs to the first plane
10083 * @param g2 belongs to the second plane
10085 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10087 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10088 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10089 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10090 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10091 gp_Vec vref(p0, p1);
10094 gp_Vec n1 = vref.Crossed(v1);
10095 gp_Vec n2 = vref.Crossed(v2);
10096 return n2.AngleWithRef(n1, vref);
10100 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10101 * The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
10102 * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
10103 * Triangles are transformed into prisms, and quadrangles into hexahedrons.
10104 * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
10105 * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list.
10106 * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created.
10107 * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
10108 * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
10109 * @param theElems - list of groups of volumes, where a group of volume is a set of
10110 * SMDS_MeshElements sorted by Id.
10111 * @param createJointElems - if TRUE, create the elements
10112 * @return TRUE if operation has been completed successfully, FALSE otherwise
10114 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10115 bool createJointElems)
10117 MESSAGE("----------------------------------------------");
10118 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10119 MESSAGE("----------------------------------------------");
10121 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10122 meshDS->BuildDownWardConnectivity(true);
10124 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10126 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10127 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10128 // build the list of nodes shared by 2 or more domains, with their domain indexes
10130 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10131 std::map<int,int>celldom; // cell vtkId --> domain
10132 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10133 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10134 faceDomains.clear();
10136 cellDomains.clear();
10137 nodeDomains.clear();
10138 std::map<int,int> emptyMap;
10139 std::set<int> emptySet;
10142 MESSAGE(".. Number of domains :"<<theElems.size());
10144 // Check if the domains do not share an element
10145 for (int idom = 0; idom < theElems.size()-1; idom++)
10147 // MESSAGE("... Check of domain #" << idom);
10148 const TIDSortedElemSet& domain = theElems[idom];
10149 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10150 for (; elemItr != domain.end(); ++elemItr)
10152 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10153 int idombisdeb = idom + 1 ;
10154 for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
10156 const TIDSortedElemSet& domainbis = theElems[idombis];
10157 if ( domainbis.count(anElem) )
10159 MESSAGE(".... Domain #" << idom);
10160 MESSAGE(".... Domain #" << idombis);
10161 throw SALOME_Exception("The domains are not disjoint.");
10168 for (int idom = 0; idom < theElems.size(); idom++)
10171 // --- build a map (face to duplicate --> volume to modify)
10172 // with all the faces shared by 2 domains (group of elements)
10173 // and corresponding volume of this domain, for each shared face.
10174 // a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
10176 MESSAGE("... Neighbors of domain #" << idom);
10177 const TIDSortedElemSet& domain = theElems[idom];
10178 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10179 for (; elemItr != domain.end(); ++elemItr)
10181 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10184 int vtkId = anElem->getVtkId();
10185 //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID());
10186 int neighborsVtkIds[NBMAXNEIGHBORS];
10187 int downIds[NBMAXNEIGHBORS];
10188 unsigned char downTypes[NBMAXNEIGHBORS];
10189 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10190 for (int n = 0; n < nbNeighbors; n++)
10192 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10193 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10194 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10197 for (int idombis = 0; idombis < theElems.size(); idombis++) // check if the neighbor belongs to another domain of the list
10199 // MESSAGE("Domain " << idombis);
10200 const TIDSortedElemSet& domainbis = theElems[idombis];
10201 if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
10203 if ( ok ) // the characteristics of the face is stored
10205 DownIdType face(downIds[n], downTypes[n]);
10206 if (!faceDomains.count(face))
10207 faceDomains[face] = emptyMap; // create an empty entry for face
10208 if (!faceDomains[face].count(idom))
10210 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10211 celldom[vtkId] = idom;
10212 //MESSAGE(" cell with a border " << vtkId << " domain " << idom);
10220 //MESSAGE("Number of shared faces " << faceDomains.size());
10221 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10223 // --- explore the shared faces domain by domain,
10224 // explore the nodes of the face and see if they belong to a cell in the domain,
10225 // which has only a node or an edge on the border (not a shared face)
10227 for (int idomain = 0; idomain < theElems.size(); idomain++)
10229 //MESSAGE("Domain " << idomain);
10230 const TIDSortedElemSet& domain = theElems[idomain];
10231 itface = faceDomains.begin();
10232 for (; itface != faceDomains.end(); ++itface)
10234 std::map<int, int> domvol = itface->second;
10235 if (!domvol.count(idomain))
10237 DownIdType face = itface->first;
10238 //MESSAGE(" --- face " << face.cellId);
10239 std::set<int> oldNodes;
10241 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10242 std::set<int>::iterator itn = oldNodes.begin();
10243 for (; itn != oldNodes.end(); ++itn)
10246 //MESSAGE(" node " << oldId);
10247 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10248 for (int i=0; i<l.ncells; i++)
10250 int vtkId = l.cells[i];
10251 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10252 if (!domain.count(anElem))
10254 int vtkType = grid->GetCellType(vtkId);
10255 int downId = grid->CellIdToDownId(vtkId);
10258 MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10259 continue; // not OK at this stage of the algorithm:
10260 //no cells created after BuildDownWardConnectivity
10262 DownIdType aCell(downId, vtkType);
10263 if (!cellDomains.count(aCell))
10264 cellDomains[aCell] = emptyMap; // create an empty entry for cell
10265 cellDomains[aCell][idomain] = vtkId;
10266 celldom[vtkId] = idomain;
10267 //MESSAGE(" cell " << vtkId << " domain " << idomain);
10273 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10274 // for each shared face, get the nodes
10275 // for each node, for each domain of the face, create a clone of the node
10277 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10278 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10279 // the value is the ordered domain ids. (more than 4 domains not taken into account)
10281 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10282 std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10283 std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10285 MESSAGE(".. Duplication of the nodes");
10286 for (int idomain = 0; idomain < theElems.size(); idomain++)
10288 itface = faceDomains.begin();
10289 for (; itface != faceDomains.end(); ++itface)
10291 std::map<int, int> domvol = itface->second;
10292 if (!domvol.count(idomain))
10294 DownIdType face = itface->first;
10295 //MESSAGE(" --- face " << face.cellId);
10296 std::set<int> oldNodes;
10298 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10299 std::set<int>::iterator itn = oldNodes.begin();
10300 for (; itn != oldNodes.end(); ++itn)
10303 //MESSAGE("-+-+-a node " << oldId);
10304 if (!nodeDomains.count(oldId))
10305 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10306 if (nodeDomains[oldId].empty())
10308 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10309 //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain);
10311 std::map<int, int>::iterator itdom = domvol.begin();
10312 for (; itdom != domvol.end(); ++itdom)
10314 int idom = itdom->first;
10315 //MESSAGE(" domain " << idom);
10316 if (!nodeDomains[oldId].count(idom)) // --- node to clone
10318 if (nodeDomains[oldId].size() >= 2) // a multiple node
10320 vector<int> orderedDoms;
10321 //MESSAGE("multiple node " << oldId);
10322 if (mutipleNodes.count(oldId))
10323 orderedDoms = mutipleNodes[oldId];
10326 map<int,int>::iterator it = nodeDomains[oldId].begin();
10327 for (; it != nodeDomains[oldId].end(); ++it)
10328 orderedDoms.push_back(it->first);
10330 orderedDoms.push_back(idom); // TODO order ==> push_front or back
10331 //stringstream txt;
10332 //for (int i=0; i<orderedDoms.size(); i++)
10333 // txt << orderedDoms[i] << " ";
10334 //MESSAGE("orderedDoms " << txt.str());
10335 mutipleNodes[oldId] = orderedDoms;
10337 double *coords = grid->GetPoint(oldId);
10338 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10339 int newId = newNode->getVtkId();
10340 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10341 //MESSAGE("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
10348 MESSAGE(".. Creation of elements");
10349 for (int idomain = 0; idomain < theElems.size(); idomain++)
10351 itface = faceDomains.begin();
10352 for (; itface != faceDomains.end(); ++itface)
10354 std::map<int, int> domvol = itface->second;
10355 if (!domvol.count(idomain))
10357 DownIdType face = itface->first;
10358 //MESSAGE(" --- face " << face.cellId);
10359 std::set<int> oldNodes;
10361 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10362 int nbMultipleNodes = 0;
10363 std::set<int>::iterator itn = oldNodes.begin();
10364 for (; itn != oldNodes.end(); ++itn)
10367 if (mutipleNodes.count(oldId))
10370 if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
10372 //MESSAGE("multiple Nodes detected on a shared face");
10373 int downId = itface->first.cellId;
10374 unsigned char cellType = itface->first.cellType;
10375 // --- shared edge or shared face ?
10376 if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10379 int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10380 for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10381 if (mutipleNodes.count(nodes[i]))
10382 if (!mutipleNodesToFace.count(nodes[i]))
10383 mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10385 else // shared face (between two volumes)
10387 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10388 const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10389 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10390 for (int ie =0; ie < nbEdges; ie++)
10393 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10394 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10396 vector<int> vn0 = mutipleNodes[nodes[0]];
10397 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10399 for (int i0 = 0; i0 < vn0.size(); i0++)
10400 for (int i1 = 0; i1 < vn1.size(); i1++)
10401 if (vn0[i0] == vn1[i1])
10402 doms.push_back(vn0[i0]);
10403 if (doms.size() >2)
10405 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10406 double *coords = grid->GetPoint(nodes[0]);
10407 gp_Pnt p0(coords[0], coords[1], coords[2]);
10408 coords = grid->GetPoint(nodes[nbNodes - 1]);
10409 gp_Pnt p1(coords[0], coords[1], coords[2]);
10411 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
10412 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10413 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10414 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10415 for (int id=0; id < doms.size(); id++)
10417 int idom = doms[id];
10418 for (int ivol=0; ivol<nbvol; ivol++)
10420 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10421 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10422 if (theElems[idom].count(elem))
10424 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10425 domvol[idom] = svol;
10426 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
10428 vtkIdType npts = 0;
10429 vtkIdType* pts = 0;
10430 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10431 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10434 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10435 angleDom[idom] = 0;
10439 gp_Pnt g(values[0], values[1], values[2]);
10440 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10441 //MESSAGE(" angle=" << angleDom[idom]);
10447 map<double, int> sortedDom; // sort domains by angle
10448 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10449 sortedDom[ia->second] = ia->first;
10450 vector<int> vnodes;
10452 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10454 vdom.push_back(ib->second);
10455 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
10457 for (int ino = 0; ino < nbNodes; ino++)
10458 vnodes.push_back(nodes[ino]);
10459 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10468 // --- iterate on shared faces (volumes to modify, face to extrude)
10469 // get node id's of the face (id SMDS = id VTK)
10470 // create flat element with old and new nodes if requested
10472 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10473 // (domain1 X domain2) = domain1 + MAXINT*domain2
10475 std::map<int, std::map<long,int> > nodeQuadDomains;
10476 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10478 MESSAGE(".. Creation of elements: simple junction");
10479 if (createJointElems)
10482 string joints2DName = "joints2D";
10483 mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
10484 SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
10485 string joints3DName = "joints3D";
10486 mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
10487 SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
10489 itface = faceDomains.begin();
10490 for (; itface != faceDomains.end(); ++itface)
10492 DownIdType face = itface->first;
10493 std::set<int> oldNodes;
10494 std::set<int>::iterator itn;
10496 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10498 std::map<int, int> domvol = itface->second;
10499 std::map<int, int>::iterator itdom = domvol.begin();
10500 int dom1 = itdom->first;
10501 int vtkVolId = itdom->second;
10503 int dom2 = itdom->first;
10504 SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
10506 stringstream grpname;
10509 grpname << dom1 << "_" << dom2;
10511 grpname << dom2 << "_" << dom1;
10512 string namegrp = grpname.str();
10513 if (!mapOfJunctionGroups.count(namegrp))
10514 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
10515 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10517 sgrp->Add(vol->GetID());
10518 if (vol->GetType() == SMDSAbs_Volume)
10519 joints3DGrp->Add(vol->GetID());
10520 else if (vol->GetType() == SMDSAbs_Face)
10521 joints2DGrp->Add(vol->GetID());
10525 // --- create volumes on multiple domain intersection if requested
10526 // iterate on mutipleNodesToFace
10527 // iterate on edgesMultiDomains
10529 MESSAGE(".. Creation of elements: multiple junction");
10530 if (createJointElems)
10532 // --- iterate on mutipleNodesToFace
10534 std::map<int, std::vector<int> >::iterator itn = mutipleNodesToFace.begin();
10535 for (; itn != mutipleNodesToFace.end(); ++itn)
10537 int node = itn->first;
10538 vector<int> orderDom = itn->second;
10539 vector<vtkIdType> orderedNodes;
10540 for (int idom = 0; idom <orderDom.size(); idom++)
10541 orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
10542 SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
10544 stringstream grpname;
10546 grpname << 0 << "_" << 0;
10548 string namegrp = grpname.str();
10549 if (!mapOfJunctionGroups.count(namegrp))
10550 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
10551 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10553 sgrp->Add(face->GetID());
10556 // --- iterate on edgesMultiDomains
10558 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
10559 for (; ite != edgesMultiDomains.end(); ++ite)
10561 vector<int> nodes = ite->first;
10562 vector<int> orderDom = ite->second;
10563 vector<vtkIdType> orderedNodes;
10564 if (nodes.size() == 2)
10566 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
10567 for (int ino=0; ino < nodes.size(); ino++)
10568 if (orderDom.size() == 3)
10569 for (int idom = 0; idom <orderDom.size(); idom++)
10570 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10572 for (int idom = orderDom.size()-1; idom >=0; idom--)
10573 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10574 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
10577 string namegrp = "jointsMultiples";
10578 if (!mapOfJunctionGroups.count(namegrp))
10579 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10580 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10582 sgrp->Add(vol->GetID());
10586 INFOS("Quadratic multiple joints not implemented");
10587 // TODO quadratic nodes
10592 // --- list the explicit faces and edges of the mesh that need to be modified,
10593 // i.e. faces and edges built with one or more duplicated nodes.
10594 // associate these faces or edges to their corresponding domain.
10595 // only the first domain found is kept when a face or edge is shared
10597 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
10598 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
10599 faceOrEdgeDom.clear();
10602 MESSAGE(".. Modification of elements");
10603 for (int idomain = 0; idomain < theElems.size(); idomain++)
10605 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
10606 for (; itnod != nodeDomains.end(); ++itnod)
10608 int oldId = itnod->first;
10609 //MESSAGE(" node " << oldId);
10610 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10611 for (int i = 0; i < l.ncells; i++)
10613 int vtkId = l.cells[i];
10614 int vtkType = grid->GetCellType(vtkId);
10615 int downId = grid->CellIdToDownId(vtkId);
10617 continue; // new cells: not to be modified
10618 DownIdType aCell(downId, vtkType);
10619 int volParents[1000];
10620 int nbvol = grid->GetParentVolumes(volParents, vtkId);
10621 for (int j = 0; j < nbvol; j++)
10622 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
10623 if (!feDom.count(vtkId))
10625 feDom[vtkId] = idomain;
10626 faceOrEdgeDom[aCell] = emptyMap;
10627 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
10628 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
10629 // << " type " << vtkType << " downId " << downId);
10635 // --- iterate on shared faces (volumes to modify, face to extrude)
10636 // get node id's of the face
10637 // replace old nodes by new nodes in volumes, and update inverse connectivity
10639 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
10640 for (int m=0; m<3; m++)
10642 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
10643 itface = (*amap).begin();
10644 for (; itface != (*amap).end(); ++itface)
10646 DownIdType face = itface->first;
10647 std::set<int> oldNodes;
10648 std::set<int>::iterator itn;
10650 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10651 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
10652 std::map<int, int> localClonedNodeIds;
10654 std::map<int, int> domvol = itface->second;
10655 std::map<int, int>::iterator itdom = domvol.begin();
10656 for (; itdom != domvol.end(); ++itdom)
10658 int idom = itdom->first;
10659 int vtkVolId = itdom->second;
10660 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
10661 localClonedNodeIds.clear();
10662 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10665 if (nodeDomains[oldId].count(idom))
10667 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10668 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
10671 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10676 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
10677 grid->BuildLinks();
10685 * \brief Double nodes on some external faces and create flat elements.
10686 * Flat elements are mainly used by some types of mechanic calculations.
10688 * Each group of the list must be constituted of faces.
10689 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10690 * @param theElems - list of groups of faces, where a group of faces is a set of
10691 * SMDS_MeshElements sorted by Id.
10692 * @return TRUE if operation has been completed successfully, FALSE otherwise
10694 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
10696 MESSAGE("-------------------------------------------------");
10697 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
10698 MESSAGE("-------------------------------------------------");
10700 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10702 // --- For each group of faces
10703 // duplicate the nodes, create a flat element based on the face
10704 // replace the nodes of the faces by their clones
10706 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
10707 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
10708 clonedNodes.clear();
10709 intermediateNodes.clear();
10710 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10711 mapOfJunctionGroups.clear();
10713 for (int idom = 0; idom < theElems.size(); idom++)
10715 const TIDSortedElemSet& domain = theElems[idom];
10716 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10717 for (; elemItr != domain.end(); ++elemItr)
10719 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10720 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
10723 // MESSAGE("aFace=" << aFace->GetID());
10724 bool isQuad = aFace->IsQuadratic();
10725 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
10727 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
10729 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
10730 while (nodeIt->more())
10732 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
10733 bool isMedium = isQuad && (aFace->IsMediumNode(node));
10735 ln2.push_back(node);
10737 ln0.push_back(node);
10739 const SMDS_MeshNode* clone = 0;
10740 if (!clonedNodes.count(node))
10742 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
10743 clonedNodes[node] = clone;
10746 clone = clonedNodes[node];
10749 ln3.push_back(clone);
10751 ln1.push_back(clone);
10753 const SMDS_MeshNode* inter = 0;
10754 if (isQuad && (!isMedium))
10756 if (!intermediateNodes.count(node))
10758 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
10759 intermediateNodes[node] = inter;
10762 inter = intermediateNodes[node];
10763 ln4.push_back(inter);
10767 // --- extrude the face
10769 vector<const SMDS_MeshNode*> ln;
10770 SMDS_MeshVolume* vol = 0;
10771 vtkIdType aType = aFace->GetVtkType();
10775 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
10776 // MESSAGE("vol prism " << vol->GetID());
10777 ln.push_back(ln1[0]);
10778 ln.push_back(ln1[1]);
10779 ln.push_back(ln1[2]);
10782 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
10783 // MESSAGE("vol hexa " << vol->GetID());
10784 ln.push_back(ln1[0]);
10785 ln.push_back(ln1[1]);
10786 ln.push_back(ln1[2]);
10787 ln.push_back(ln1[3]);
10789 case VTK_QUADRATIC_TRIANGLE:
10790 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
10791 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
10792 // MESSAGE("vol quad prism " << vol->GetID());
10793 ln.push_back(ln1[0]);
10794 ln.push_back(ln1[1]);
10795 ln.push_back(ln1[2]);
10796 ln.push_back(ln3[0]);
10797 ln.push_back(ln3[1]);
10798 ln.push_back(ln3[2]);
10800 case VTK_QUADRATIC_QUAD:
10801 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
10802 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
10803 // ln4[0], ln4[1], ln4[2], ln4[3]);
10804 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
10805 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
10806 ln4[0], ln4[1], ln4[2], ln4[3]);
10807 // MESSAGE("vol quad hexa " << vol->GetID());
10808 ln.push_back(ln1[0]);
10809 ln.push_back(ln1[1]);
10810 ln.push_back(ln1[2]);
10811 ln.push_back(ln1[3]);
10812 ln.push_back(ln3[0]);
10813 ln.push_back(ln3[1]);
10814 ln.push_back(ln3[2]);
10815 ln.push_back(ln3[3]);
10825 stringstream grpname;
10829 string namegrp = grpname.str();
10830 if (!mapOfJunctionGroups.count(namegrp))
10831 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10832 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10834 sgrp->Add(vol->GetID());
10837 // --- modify the face
10839 aFace->ChangeNodes(&ln[0], ln.size());
10846 * \brief identify all the elements around a geom shape, get the faces delimiting the hole
10847 * Build groups of volume to remove, groups of faces to replace on the skin of the object,
10848 * groups of faces to remove inside the object, (idem edges).
10849 * Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
10851 void SMESH_MeshEditor::CreateHoleSkin(double radius,
10852 const TopoDS_Shape& theShape,
10853 SMESH_NodeSearcher* theNodeSearcher,
10854 const char* groupName,
10855 std::vector<double>& nodesCoords,
10856 std::vector<std::vector<int> >& listOfListOfNodes)
10858 MESSAGE("--------------------------------");
10859 MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
10860 MESSAGE("--------------------------------");
10862 // --- zone of volumes to remove is given :
10863 // 1 either by a geom shape (one or more vertices) and a radius,
10864 // 2 either by a group of nodes (representative of the shape)to use with the radius,
10865 // 3 either by a group of nodes where all the elements build on one of this nodes are to remove,
10866 // In the case 2, the group of nodes is an external group of nodes from another mesh,
10867 // In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
10868 // defined by it's name.
10870 SMESHDS_GroupBase* groupDS = 0;
10871 SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
10872 while ( groupIt->more() )
10875 SMESH_Group * group = groupIt->next();
10876 if ( !group ) continue;
10877 groupDS = group->GetGroupDS();
10878 if ( !groupDS || groupDS->IsEmpty() ) continue;
10879 std::string grpName = group->GetName();
10880 //MESSAGE("grpName=" << grpName);
10881 if (grpName == groupName)
10887 bool isNodeGroup = false;
10888 bool isNodeCoords = false;
10891 if (groupDS->GetType() != SMDSAbs_Node)
10893 isNodeGroup = true; // a group of nodes exists and it is in this mesh
10896 if (nodesCoords.size() > 0)
10897 isNodeCoords = true; // a list o nodes given by their coordinates
10898 //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
10900 // --- define groups to build
10902 int idg; // --- group of SMDS volumes
10903 string grpvName = groupName;
10904 grpvName += "_vol";
10905 SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
10908 MESSAGE("group not created " << grpvName);
10911 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
10913 int idgs; // --- group of SMDS faces on the skin
10914 string grpsName = groupName;
10915 grpsName += "_skin";
10916 SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
10919 MESSAGE("group not created " << grpsName);
10922 SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
10924 int idgi; // --- group of SMDS faces internal (several shapes)
10925 string grpiName = groupName;
10926 grpiName += "_internalFaces";
10927 SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
10930 MESSAGE("group not created " << grpiName);
10933 SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
10935 int idgei; // --- group of SMDS faces internal (several shapes)
10936 string grpeiName = groupName;
10937 grpeiName += "_internalEdges";
10938 SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
10941 MESSAGE("group not created " << grpeiName);
10944 SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
10946 // --- build downward connectivity
10948 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10949 meshDS->BuildDownWardConnectivity(true);
10950 SMDS_UnstructuredGrid* grid = meshDS->getGrid();
10952 // --- set of volumes detected inside
10954 std::set<int> setOfInsideVol;
10955 std::set<int> setOfVolToCheck;
10957 std::vector<gp_Pnt> gpnts;
10960 if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
10962 MESSAGE("group of nodes provided");
10963 SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
10964 while ( elemIt->more() )
10966 const SMDS_MeshElement* elem = elemIt->next();
10969 const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
10972 SMDS_MeshElement* vol = 0;
10973 SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
10974 while (volItr->more())
10976 vol = (SMDS_MeshElement*)volItr->next();
10977 setOfInsideVol.insert(vol->getVtkId());
10978 sgrp->Add(vol->GetID());
10982 else if (isNodeCoords)
10984 MESSAGE("list of nodes coordinates provided");
10987 while (i < nodesCoords.size()-2)
10989 double x = nodesCoords[i++];
10990 double y = nodesCoords[i++];
10991 double z = nodesCoords[i++];
10992 gp_Pnt p = gp_Pnt(x, y ,z);
10993 gpnts.push_back(p);
10994 MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
10998 else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
11000 MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
11001 TopTools_IndexedMapOfShape vertexMap;
11002 TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
11003 gp_Pnt p = gp_Pnt(0,0,0);
11004 if (vertexMap.Extent() < 1)
11007 for ( int i = 1; i <= vertexMap.Extent(); ++i )
11009 const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
11010 p = BRep_Tool::Pnt(vertex);
11011 gpnts.push_back(p);
11012 MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
11016 if (gpnts.size() > 0)
11019 const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
11021 nodeId = startNode->GetID();
11022 MESSAGE("nodeId " << nodeId);
11024 double radius2 = radius*radius;
11025 MESSAGE("radius2 " << radius2);
11027 // --- volumes on start node
11029 setOfVolToCheck.clear();
11030 SMDS_MeshElement* startVol = 0;
11031 SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
11032 while (volItr->more())
11034 startVol = (SMDS_MeshElement*)volItr->next();
11035 setOfVolToCheck.insert(startVol->getVtkId());
11037 if (setOfVolToCheck.empty())
11039 MESSAGE("No volumes found");
11043 // --- starting with central volumes then their neighbors, check if they are inside
11044 // or outside the domain, until no more new neighbor volume is inside.
11045 // Fill the group of inside volumes
11047 std::map<int, double> mapOfNodeDistance2;
11048 mapOfNodeDistance2.clear();
11049 std::set<int> setOfOutsideVol;
11050 while (!setOfVolToCheck.empty())
11052 std::set<int>::iterator it = setOfVolToCheck.begin();
11054 MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11055 bool volInside = false;
11056 vtkIdType npts = 0;
11057 vtkIdType* pts = 0;
11058 grid->GetCellPoints(vtkId, npts, pts);
11059 for (int i=0; i<npts; i++)
11061 double distance2 = 0;
11062 if (mapOfNodeDistance2.count(pts[i]))
11064 distance2 = mapOfNodeDistance2[pts[i]];
11065 MESSAGE("point " << pts[i] << " distance2 " << distance2);
11069 double *coords = grid->GetPoint(pts[i]);
11070 gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
11072 for (int j=0; j<gpnts.size(); j++)
11074 double d2 = aPoint.SquareDistance(gpnts[j]);
11075 if (d2 < distance2)
11078 if (distance2 < radius2)
11082 mapOfNodeDistance2[pts[i]] = distance2;
11083 MESSAGE(" point " << pts[i] << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " << coords[2]);
11085 if (distance2 < radius2)
11087 volInside = true; // one or more nodes inside the domain
11088 sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11094 setOfInsideVol.insert(vtkId);
11095 MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11096 int neighborsVtkIds[NBMAXNEIGHBORS];
11097 int downIds[NBMAXNEIGHBORS];
11098 unsigned char downTypes[NBMAXNEIGHBORS];
11099 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11100 for (int n = 0; n < nbNeighbors; n++)
11101 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
11102 setOfVolToCheck.insert(neighborsVtkIds[n]);
11106 setOfOutsideVol.insert(vtkId);
11107 MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11109 setOfVolToCheck.erase(vtkId);
11113 // --- for outside hexahedrons, check if they have more than one neighbor volume inside
11114 // If yes, add the volume to the inside set
11116 bool addedInside = true;
11117 std::set<int> setOfVolToReCheck;
11118 while (addedInside)
11120 MESSAGE(" --------------------------- re check");
11121 addedInside = false;
11122 std::set<int>::iterator itv = setOfInsideVol.begin();
11123 for (; itv != setOfInsideVol.end(); ++itv)
11126 int neighborsVtkIds[NBMAXNEIGHBORS];
11127 int downIds[NBMAXNEIGHBORS];
11128 unsigned char downTypes[NBMAXNEIGHBORS];
11129 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11130 for (int n = 0; n < nbNeighbors; n++)
11131 if (!setOfInsideVol.count(neighborsVtkIds[n]))
11132 setOfVolToReCheck.insert(neighborsVtkIds[n]);
11134 setOfVolToCheck = setOfVolToReCheck;
11135 setOfVolToReCheck.clear();
11136 while (!setOfVolToCheck.empty())
11138 std::set<int>::iterator it = setOfVolToCheck.begin();
11140 if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
11142 MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11143 int countInside = 0;
11144 int neighborsVtkIds[NBMAXNEIGHBORS];
11145 int downIds[NBMAXNEIGHBORS];
11146 unsigned char downTypes[NBMAXNEIGHBORS];
11147 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11148 for (int n = 0; n < nbNeighbors; n++)
11149 if (setOfInsideVol.count(neighborsVtkIds[n]))
11151 MESSAGE("countInside " << countInside);
11152 if (countInside > 1)
11154 MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11155 setOfInsideVol.insert(vtkId);
11156 sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11157 addedInside = true;
11160 setOfVolToReCheck.insert(vtkId);
11162 setOfVolToCheck.erase(vtkId);
11166 // --- map of Downward faces at the boundary, inside the global volume
11167 // map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
11168 // fill group of SMDS faces inside the volume (when several volume shapes)
11169 // fill group of SMDS faces on the skin of the global volume (if skin)
11171 std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
11172 std::map<DownIdType, int, DownIdCompare> skinFaces; // faces on the skin of the global volume --> corresponding cell
11173 std::set<int>::iterator it = setOfInsideVol.begin();
11174 for (; it != setOfInsideVol.end(); ++it)
11177 //MESSAGE(" vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11178 int neighborsVtkIds[NBMAXNEIGHBORS];
11179 int downIds[NBMAXNEIGHBORS];
11180 unsigned char downTypes[NBMAXNEIGHBORS];
11181 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
11182 for (int n = 0; n < nbNeighbors; n++)
11184 int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
11185 if (neighborDim == 3)
11187 if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
11189 DownIdType face(downIds[n], downTypes[n]);
11190 boundaryFaces[face] = vtkId;
11192 // if the face between to volumes is in the mesh, get it (internal face between shapes)
11193 int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11194 if (vtkFaceId >= 0)
11196 sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
11197 // find also the smds edges on this face
11198 int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
11199 const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
11200 const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
11201 for (int i = 0; i < nbEdges; i++)
11203 int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
11204 if (vtkEdgeId >= 0)
11205 sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
11209 else if (neighborDim == 2) // skin of the volume
11211 DownIdType face(downIds[n], downTypes[n]);
11212 skinFaces[face] = vtkId;
11213 int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11214 if (vtkFaceId >= 0)
11215 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
11220 // --- identify the edges constituting the wire of each subshape on the skin
11221 // define polylines with the nodes of edges, equivalent to wires
11222 // project polylines on subshapes, and partition, to get geom faces
11224 std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
11225 std::set<int> emptySet;
11227 std::set<int> shapeIds;
11229 SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
11230 while (itelem->more())
11232 const SMDS_MeshElement *elem = itelem->next();
11233 int shapeId = elem->getshapeId();
11234 int vtkId = elem->getVtkId();
11235 if (!shapeIdToVtkIdSet.count(shapeId))
11237 shapeIdToVtkIdSet[shapeId] = emptySet;
11238 shapeIds.insert(shapeId);
11240 shapeIdToVtkIdSet[shapeId].insert(vtkId);
11243 std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
11244 std::set<DownIdType, DownIdCompare> emptyEdges;
11245 emptyEdges.clear();
11247 std::map<int, std::set<int> >::iterator itShape = shapeIdToVtkIdSet.begin();
11248 for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
11250 int shapeId = itShape->first;
11251 MESSAGE(" --- Shape ID --- "<< shapeId);
11252 shapeIdToEdges[shapeId] = emptyEdges;
11254 std::vector<int> nodesEdges;
11256 std::set<int>::iterator its = itShape->second.begin();
11257 for (; its != itShape->second.end(); ++its)
11260 MESSAGE(" " << vtkId);
11261 int neighborsVtkIds[NBMAXNEIGHBORS];
11262 int downIds[NBMAXNEIGHBORS];
11263 unsigned char downTypes[NBMAXNEIGHBORS];
11264 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11265 for (int n = 0; n < nbNeighbors; n++)
11267 if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
11269 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11270 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11271 if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
11273 DownIdType edge(downIds[n], downTypes[n]);
11274 if (!shapeIdToEdges[shapeId].count(edge))
11276 shapeIdToEdges[shapeId].insert(edge);
11278 int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
11279 nodesEdges.push_back(vtkNodeId[0]);
11280 nodesEdges.push_back(vtkNodeId[nbNodes-1]);
11281 MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
11287 std::list<int> order;
11289 if (nodesEdges.size() > 0)
11291 order.push_back(nodesEdges[0]); MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1;
11292 nodesEdges[0] = -1;
11293 order.push_back(nodesEdges[1]); MESSAGE(" --- back " << order.back()+1);
11294 nodesEdges[1] = -1; // do not reuse this edge
11298 int nodeTofind = order.back(); // try first to push back
11300 for (i = 0; i<nodesEdges.size(); i++)
11301 if (nodesEdges[i] == nodeTofind)
11303 if (i == nodesEdges.size())
11304 found = false; // no follower found on back
11307 if (i%2) // odd ==> use the previous one
11308 if (nodesEdges[i-1] < 0)
11312 order.push_back(nodesEdges[i-1]); MESSAGE(" --- back " << order.back()+1);
11313 nodesEdges[i-1] = -1;
11315 else // even ==> use the next one
11316 if (nodesEdges[i+1] < 0)
11320 order.push_back(nodesEdges[i+1]); MESSAGE(" --- back " << order.back()+1);
11321 nodesEdges[i+1] = -1;
11326 // try to push front
11328 nodeTofind = order.front(); // try to push front
11329 for (i = 0; i<nodesEdges.size(); i++)
11330 if (nodesEdges[i] == nodeTofind)
11332 if (i == nodesEdges.size())
11334 found = false; // no predecessor found on front
11337 if (i%2) // odd ==> use the previous one
11338 if (nodesEdges[i-1] < 0)
11342 order.push_front(nodesEdges[i-1]); MESSAGE(" --- front " << order.front()+1);
11343 nodesEdges[i-1] = -1;
11345 else // even ==> use the next one
11346 if (nodesEdges[i+1] < 0)
11350 order.push_front(nodesEdges[i+1]); MESSAGE(" --- front " << order.front()+1);
11351 nodesEdges[i+1] = -1;
11357 std::vector<int> nodes;
11358 nodes.push_back(shapeId);
11359 std::list<int>::iterator itl = order.begin();
11360 for (; itl != order.end(); itl++)
11362 nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
11363 MESSAGE(" ordered node " << nodes[nodes.size()-1]);
11365 listOfListOfNodes.push_back(nodes);
11368 // partition geom faces with blocFissure
11369 // mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
11370 // mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
11376 //================================================================================
11378 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11379 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11380 * \return TRUE if operation has been completed successfully, FALSE otherwise
11382 //================================================================================
11384 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11386 // iterates on volume elements and detect all free faces on them
11387 SMESHDS_Mesh* aMesh = GetMeshDS();
11390 //bool res = false;
11391 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11392 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11395 const SMDS_MeshVolume* volume = vIt->next();
11396 SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11397 vTool.SetExternalNormal();
11398 //const bool isPoly = volume->IsPoly();
11399 const int iQuad = volume->IsQuadratic();
11400 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11402 if (!vTool.IsFreeFace(iface))
11405 vector<const SMDS_MeshNode *> nodes;
11406 int nbFaceNodes = vTool.NbFaceNodes(iface);
11407 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11409 for ( ; inode < nbFaceNodes; inode += iQuad+1)
11410 nodes.push_back(faceNodes[inode]);
11411 if (iQuad) { // add medium nodes
11412 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11413 nodes.push_back(faceNodes[inode]);
11414 if ( nbFaceNodes == 9 ) // bi-quadratic quad
11415 nodes.push_back(faceNodes[8]);
11417 // add new face based on volume nodes
11418 if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11420 continue; // face already exsist
11422 AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11426 return ( nbFree==(nbExisted+nbCreated) );
11431 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11433 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11435 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11438 //================================================================================
11440 * \brief Creates missing boundary elements
11441 * \param elements - elements whose boundary is to be checked
11442 * \param dimension - defines type of boundary elements to create
11443 * \param group - a group to store created boundary elements in
11444 * \param targetMesh - a mesh to store created boundary elements in
11445 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11446 * \param toCopyExistingBoundary - if true, not only new but also pre-existing
11447 * boundary elements will be copied into the targetMesh
11448 * \param toAddExistingBondary - if true, not only new but also pre-existing
11449 * boundary elements will be added into the new group
11450 * \param aroundElements - if true, elements will be created on boundary of given
11451 * elements else, on boundary of the whole mesh.
11452 * \return nb of added boundary elements
11454 //================================================================================
11456 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11457 Bnd_Dimension dimension,
11458 SMESH_Group* group/*=0*/,
11459 SMESH_Mesh* targetMesh/*=0*/,
11460 bool toCopyElements/*=false*/,
11461 bool toCopyExistingBoundary/*=false*/,
11462 bool toAddExistingBondary/*= false*/,
11463 bool aroundElements/*= false*/)
11465 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11466 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11467 // hope that all elements are of the same type, do not check them all
11468 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11469 throw SALOME_Exception(LOCALIZED("wrong element type"));
11472 toCopyElements = toCopyExistingBoundary = false;
11474 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11475 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11476 int nbAddedBnd = 0;
11478 // editor adding present bnd elements and optionally holding elements to add to the group
11479 SMESH_MeshEditor* presentEditor;
11480 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11481 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11483 SMESH_MesherHelper helper( *myMesh );
11484 const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11485 SMDS_VolumeTool vTool;
11486 TIDSortedElemSet avoidSet;
11487 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11490 typedef vector<const SMDS_MeshNode*> TConnectivity;
11492 SMDS_ElemIteratorPtr eIt;
11493 if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11494 else eIt = elemSetIterator( elements );
11496 while (eIt->more())
11498 const SMDS_MeshElement* elem = eIt->next();
11499 const int iQuad = elem->IsQuadratic();
11501 // ------------------------------------------------------------------------------------
11502 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11503 // ------------------------------------------------------------------------------------
11504 vector<const SMDS_MeshElement*> presentBndElems;
11505 vector<TConnectivity> missingBndElems;
11506 TConnectivity nodes, elemNodes;
11507 if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11509 vTool.SetExternalNormal();
11510 const SMDS_MeshElement* otherVol = 0;
11511 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11513 if ( !vTool.IsFreeFace(iface, &otherVol) &&
11514 ( !aroundElements || elements.count( otherVol )))
11516 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11517 const int nbFaceNodes = vTool.NbFaceNodes (iface);
11518 if ( missType == SMDSAbs_Edge ) // boundary edges
11520 nodes.resize( 2+iQuad );
11521 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11523 for ( int j = 0; j < nodes.size(); ++j )
11525 if ( const SMDS_MeshElement* edge =
11526 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11527 presentBndElems.push_back( edge );
11529 missingBndElems.push_back( nodes );
11532 else // boundary face
11535 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11536 nodes.push_back( nn[inode] ); // add corner nodes
11538 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11539 nodes.push_back( nn[inode] ); // add medium nodes
11540 int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11542 nodes.push_back( vTool.GetNodes()[ iCenter ] );
11544 if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11545 SMDSAbs_Face, /*noMedium=*/false ))
11546 presentBndElems.push_back( f );
11548 missingBndElems.push_back( nodes );
11550 if ( targetMesh != myMesh )
11552 // add 1D elements on face boundary to be added to a new mesh
11553 const SMDS_MeshElement* edge;
11554 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11557 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11559 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11560 if ( edge && avoidSet.insert( edge ).second )
11561 presentBndElems.push_back( edge );
11567 else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
11569 avoidSet.clear(), avoidSet.insert( elem );
11570 elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
11571 SMDS_MeshElement::iterator() );
11572 elemNodes.push_back( elemNodes[0] );
11573 nodes.resize( 2 + iQuad );
11574 const int nbLinks = elem->NbCornerNodes();
11575 for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
11577 nodes[0] = elemNodes[iN];
11578 nodes[1] = elemNodes[iN+1+iQuad];
11579 if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11580 continue; // not free link
11582 if ( iQuad ) nodes[2] = elemNodes[iN+1];
11583 if ( const SMDS_MeshElement* edge =
11584 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11585 presentBndElems.push_back( edge );
11587 missingBndElems.push_back( nodes );
11591 // ---------------------------------
11592 // 2. Add missing boundary elements
11593 // ---------------------------------
11594 if ( targetMesh != myMesh )
11595 // instead of making a map of nodes in this mesh and targetMesh,
11596 // we create nodes with same IDs.
11597 for ( int i = 0; i < missingBndElems.size(); ++i )
11599 TConnectivity& srcNodes = missingBndElems[i];
11600 TConnectivity nodes( srcNodes.size() );
11601 for ( inode = 0; inode < nodes.size(); ++inode )
11602 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11603 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11605 /*noMedium=*/false))
11607 tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11611 for ( int i = 0; i < missingBndElems.size(); ++i )
11613 TConnectivity& nodes = missingBndElems[i];
11614 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11616 /*noMedium=*/false))
11618 SMDS_MeshElement* elem =
11619 tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11622 // try to set a new element to a shape
11623 if ( myMesh->HasShapeToMesh() )
11626 set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11627 const int nbN = nodes.size() / (iQuad+1 );
11628 for ( inode = 0; inode < nbN && ok; ++inode )
11630 pair<int, TopAbs_ShapeEnum> i_stype =
11631 helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11632 if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11633 mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11635 if ( ok && mediumShapes.size() > 1 )
11637 set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11638 pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11639 for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11641 if (( ok = ( stype_i->first != stype_i_0.first )))
11642 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11643 aMesh->IndexToShape( stype_i_0.second ));
11646 if ( ok && mediumShapes.begin()->first == missShapeType )
11647 aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11651 // ----------------------------------
11652 // 3. Copy present boundary elements
11653 // ----------------------------------
11654 if ( toCopyExistingBoundary )
11655 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11657 const SMDS_MeshElement* e = presentBndElems[i];
11658 TConnectivity nodes( e->NbNodes() );
11659 for ( inode = 0; inode < nodes.size(); ++inode )
11660 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11661 presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11663 else // store present elements to add them to a group
11664 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11666 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11669 } // loop on given elements
11671 // ---------------------------------------------
11672 // 4. Fill group with boundary elements
11673 // ---------------------------------------------
11676 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11677 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11678 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11680 tgtEditor.myLastCreatedElems.Clear();
11681 tgtEditor2.myLastCreatedElems.Clear();
11683 // -----------------------
11684 // 5. Copy given elements
11685 // -----------------------
11686 if ( toCopyElements && targetMesh != myMesh )
11688 if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11689 else eIt = elemSetIterator( elements );
11690 while (eIt->more())
11692 const SMDS_MeshElement* elem = eIt->next();
11693 TConnectivity nodes( elem->NbNodes() );
11694 for ( inode = 0; inode < nodes.size(); ++inode )
11695 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11696 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11698 tgtEditor.myLastCreatedElems.Clear();