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 TTElemOfElemListMap & 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 TTElemOfElemListMap::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 TTElemOfElemListMap 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 TTElemOfElemListMap& 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 TTElemOfElemListMap& 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 ( SMESH_Algo::isDegenerated( 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 ( !theTrack->HasShapeToMesh() ) {
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 ( SMESH_Algo::isDegenerated( aTrackEdge ) )
5268 return EXTR_BAD_PATH_SHAPE;
5269 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5270 const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
5271 const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
5272 // starting node must be aN1 or aN2
5273 if ( !( aN1 == theN1 || aN2 == theN1 ) )
5274 return EXTR_BAD_STARTING_NODE;
5275 aItN = pMeshDS->nodesIterator();
5276 while ( aItN->more() ) {
5277 const SMDS_MeshNode* pNode = aItN->next();
5278 if( pNode==aN1 || pNode==aN2 ) continue;
5279 const SMDS_EdgePosition* pEPos =
5280 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5281 double aT = pEPos->GetUParameter();
5282 aPrms.push_back( aT );
5284 //Extrusion_Error err =
5285 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5287 else if( aS.ShapeType() == TopAbs_WIRE ) {
5288 list< SMESH_subMesh* > LSM;
5289 TopTools_SequenceOfShape Edges;
5290 TopExp_Explorer eExp(aS, TopAbs_EDGE);
5291 for(; eExp.More(); eExp.Next()) {
5292 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5293 if( SMESH_Algo::isDegenerated(E) ) continue;
5294 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5300 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5301 TopoDS_Vertex aVprev;
5302 TColStd_MapOfInteger UsedNums;
5303 int NbEdges = Edges.Length();
5305 for(; i<=NbEdges; i++) {
5307 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5308 for(; itLSM!=LSM.end(); itLSM++) {
5310 if(UsedNums.Contains(k)) continue;
5311 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5312 SMESH_subMesh* locTrack = *itLSM;
5313 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5314 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5315 bool aN1isOK = false, aN2isOK = false;
5316 if ( aVprev.IsNull() ) {
5317 // if previous vertex is not yet defined, it means that we in the beginning of wire
5318 // and we have to find initial vertex corresponding to starting node theN1
5319 const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
5320 const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
5321 // starting node must be aN1 or aN2
5322 aN1isOK = ( aN1 && aN1 == theN1 );
5323 aN2isOK = ( aN2 && aN2 == theN1 );
5326 // we have specified ending vertex of the previous edge on the previous iteration
5327 // and we have just to check that it corresponds to any vertex in current segment
5328 aN1isOK = aVprev.IsSame( aV1 );
5329 aN2isOK = aVprev.IsSame( aV2 );
5331 if ( !aN1isOK && !aN2isOK ) continue;
5332 // 2. Collect parameters on the track edge
5334 aItN = locMeshDS->GetNodes();
5335 while ( aItN->more() ) {
5336 const SMDS_MeshNode* pNode = aItN->next();
5337 const SMDS_EdgePosition* pEPos =
5338 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5339 double aT = pEPos->GetUParameter();
5340 aPrms.push_back( aT );
5342 list<SMESH_MeshEditor_PathPoint> LPP;
5343 //Extrusion_Error err =
5344 MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5345 LLPPs.push_back(LPP);
5347 // update startN for search following egde
5348 if ( aN1isOK ) aVprev = aV2;
5353 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5354 list<SMESH_MeshEditor_PathPoint>& firstList = *itLLPP;
5355 fullList.splice( fullList.end(), firstList );
5357 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5358 fullList.pop_back();
5360 for(; itLLPP!=LLPPs.end(); itLLPP++) {
5361 list<SMESH_MeshEditor_PathPoint>& currList = *itLLPP;
5362 SMESH_MeshEditor_PathPoint PP2 = currList.front();
5363 gp_Dir D1 = PP1.Tangent();
5364 gp_Dir D2 = PP2.Tangent();
5365 gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5366 PP1.SetTangent(Dnew);
5367 fullList.push_back(PP1);
5368 fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() );
5369 PP1 = fullList.back();
5370 fullList.pop_back();
5372 // if wire not closed
5373 fullList.push_back(PP1);
5377 return EXTR_BAD_PATH_SHAPE;
5380 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5381 theHasRefPoint, theRefPoint, theMakeGroups);
5385 //=======================================================================
5386 //function : MakeEdgePathPoints
5387 //purpose : auxilary for ExtrusionAlongTrack
5388 //=======================================================================
5389 SMESH_MeshEditor::Extrusion_Error
5390 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5391 const TopoDS_Edge& aTrackEdge,
5393 list<SMESH_MeshEditor_PathPoint>& LPP)
5395 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5397 aTolVec2=aTolVec*aTolVec;
5399 TopoDS_Vertex aV1, aV2;
5400 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5401 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5402 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5403 // 2. Collect parameters on the track edge
5404 aPrms.push_front( aT1 );
5405 aPrms.push_back( aT2 );
5408 if( FirstIsStart ) {
5419 SMESH_MeshEditor_PathPoint aPP;
5420 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5421 std::list<double>::iterator aItD = aPrms.begin();
5422 for(; aItD != aPrms.end(); ++aItD) {
5426 aC3D->D1( aT, aP3D, aVec );
5427 aL2 = aVec.SquareMagnitude();
5428 if ( aL2 < aTolVec2 )
5429 return EXTR_CANT_GET_TANGENT;
5430 gp_Dir aTgt( aVec );
5432 aPP.SetTangent( aTgt );
5433 aPP.SetParameter( aT );
5440 //=======================================================================
5441 //function : MakeExtrElements
5442 //purpose : auxilary for ExtrusionAlongTrack
5443 //=======================================================================
5444 SMESH_MeshEditor::Extrusion_Error
5445 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5446 list<SMESH_MeshEditor_PathPoint>& fullList,
5447 const bool theHasAngles,
5448 list<double>& theAngles,
5449 const bool theLinearVariation,
5450 const bool theHasRefPoint,
5451 const gp_Pnt& theRefPoint,
5452 const bool theMakeGroups)
5454 const int aNbTP = fullList.size();
5456 if( theHasAngles && !theAngles.empty() && theLinearVariation )
5457 LinearAngleVariation(aNbTP-1, theAngles);
5458 // fill vector of path points with angles
5459 vector<SMESH_MeshEditor_PathPoint> aPPs;
5460 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5461 list<double>::iterator itAngles = theAngles.begin();
5462 aPPs.push_back( *itPP++ );
5463 for( ; itPP != fullList.end(); itPP++) {
5464 aPPs.push_back( *itPP );
5465 if ( theHasAngles && itAngles != theAngles.end() )
5466 aPPs.back().SetAngle( *itAngles );
5469 TNodeOfNodeListMap mapNewNodes;
5470 TElemOfVecOfNnlmiMap mapElemNewNodes;
5471 TTElemOfElemListMap newElemsMap;
5472 TIDSortedElemSet::iterator itElem;
5473 // source elements for each generated one
5474 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5476 // 3. Center of rotation aV0
5477 gp_Pnt aV0 = theRefPoint;
5478 if ( !theHasRefPoint )
5480 gp_XYZ aGC( 0.,0.,0. );
5481 TIDSortedElemSet newNodes;
5483 itElem = theElements.begin();
5484 for ( ; itElem != theElements.end(); itElem++ ) {
5485 const SMDS_MeshElement* elem = *itElem;
5487 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5488 while ( itN->more() ) {
5489 const SMDS_MeshElement* node = itN->next();
5490 if ( newNodes.insert( node ).second )
5491 aGC += SMESH_TNodeXYZ( node );
5494 aGC /= newNodes.size();
5496 } // if (!theHasRefPoint) {
5498 // 4. Processing the elements
5499 SMESHDS_Mesh* aMesh = GetMeshDS();
5501 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5502 // check element type
5503 const SMDS_MeshElement* elem = *itElem;
5504 SMDSAbs_ElementType aTypeE = elem->GetType();
5505 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5508 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5509 newNodesItVec.reserve( elem->NbNodes() );
5511 // loop on elem nodes
5513 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5514 while ( itN->more() )
5517 // check if a node has been already processed
5518 const SMDS_MeshNode* node =
5519 static_cast<const SMDS_MeshNode*>( itN->next() );
5520 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5521 if ( nIt == mapNewNodes.end() ) {
5522 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5523 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5526 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5527 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5528 gp_Ax1 anAx1, anAxT1T0;
5529 gp_Dir aDT1x, aDT0x, aDT1T0;
5534 aPN0 = SMESH_TNodeXYZ( node );
5536 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5538 aDT0x= aPP0.Tangent();
5539 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5541 for ( int j = 1; j < aNbTP; ++j ) {
5542 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5544 aDT1x = aPP1.Tangent();
5545 aAngle1x = aPP1.Angle();
5547 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5549 gp_Vec aV01x( aP0x, aP1x );
5550 aTrsf.SetTranslation( aV01x );
5553 aV1x = aV0x.Transformed( aTrsf );
5554 aPN1 = aPN0.Transformed( aTrsf );
5556 // rotation 1 [ T1,T0 ]
5557 aAngleT1T0=-aDT1x.Angle( aDT0x );
5558 if (fabs(aAngleT1T0) > aTolAng) {
5560 anAxT1T0.SetLocation( aV1x );
5561 anAxT1T0.SetDirection( aDT1T0 );
5562 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5564 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5568 if ( theHasAngles ) {
5569 anAx1.SetLocation( aV1x );
5570 anAx1.SetDirection( aDT1x );
5571 aTrsfRot.SetRotation( anAx1, aAngle1x );
5573 aPN1 = aPN1.Transformed( aTrsfRot );
5577 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5578 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5579 // create additional node
5580 double x = ( aPN1.X() + aPN0.X() )/2.;
5581 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5582 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5583 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5584 myLastCreatedNodes.Append(newNode);
5585 srcNodes.Append( node );
5586 listNewNodes.push_back( newNode );
5588 const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() );
5589 myLastCreatedNodes.Append(newNode);
5590 srcNodes.Append( node );
5591 listNewNodes.push_back( newNode );
5601 // if current elem is quadratic and current node is not medium
5602 // we have to check - may be it is needed to insert additional nodes
5603 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5604 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5605 if(listNewNodes.size()==aNbTP-1) {
5606 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5607 gp_XYZ P(node->X(), node->Y(), node->Z());
5608 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5610 for(i=0; i<aNbTP-1; i++) {
5611 const SMDS_MeshNode* N = *it;
5612 double x = ( N->X() + P.X() )/2.;
5613 double y = ( N->Y() + P.Y() )/2.;
5614 double z = ( N->Z() + P.Z() )/2.;
5615 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5616 srcNodes.Append( node );
5617 myLastCreatedNodes.Append(newN);
5620 P = gp_XYZ(N->X(),N->Y(),N->Z());
5622 listNewNodes.clear();
5623 for(i=0; i<2*(aNbTP-1); i++) {
5624 listNewNodes.push_back(aNodes[i]);
5630 newNodesItVec.push_back( nIt );
5632 // make new elements
5633 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5634 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5635 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5638 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5640 if ( theMakeGroups )
5641 generateGroups( srcNodes, srcElems, "extruded");
5647 //=======================================================================
5648 //function : LinearAngleVariation
5649 //purpose : auxilary for ExtrusionAlongTrack
5650 //=======================================================================
5651 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5652 list<double>& Angles)
5654 int nbAngles = Angles.size();
5655 if( nbSteps > nbAngles ) {
5656 vector<double> theAngles(nbAngles);
5657 list<double>::iterator it = Angles.begin();
5659 for(; it!=Angles.end(); it++) {
5661 theAngles[i] = (*it);
5664 double rAn2St = double( nbAngles ) / double( nbSteps );
5665 double angPrev = 0, angle;
5666 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5667 double angCur = rAn2St * ( iSt+1 );
5668 double angCurFloor = floor( angCur );
5669 double angPrevFloor = floor( angPrev );
5670 if ( angPrevFloor == angCurFloor )
5671 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5673 int iP = int( angPrevFloor );
5674 double angPrevCeil = ceil(angPrev);
5675 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5677 int iC = int( angCurFloor );
5678 if ( iC < nbAngles )
5679 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5681 iP = int( angPrevCeil );
5683 angle += theAngles[ iC ];
5685 res.push_back(angle);
5690 for(; it!=res.end(); it++)
5691 Angles.push_back( *it );
5696 //================================================================================
5698 * \brief Move or copy theElements applying theTrsf to their nodes
5699 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5700 * \param theTrsf - transformation to apply
5701 * \param theCopy - if true, create translated copies of theElems
5702 * \param theMakeGroups - if true and theCopy, create translated groups
5703 * \param theTargetMesh - mesh to copy translated elements into
5704 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5706 //================================================================================
5708 SMESH_MeshEditor::PGroupIDs
5709 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5710 const gp_Trsf& theTrsf,
5712 const bool theMakeGroups,
5713 SMESH_Mesh* theTargetMesh)
5715 myLastCreatedElems.Clear();
5716 myLastCreatedNodes.Clear();
5718 bool needReverse = false;
5719 string groupPostfix;
5720 switch ( theTrsf.Form() ) {
5722 MESSAGE("gp_PntMirror");
5724 groupPostfix = "mirrored";
5727 MESSAGE("gp_Ax1Mirror");
5728 groupPostfix = "mirrored";
5731 MESSAGE("gp_Ax2Mirror");
5733 groupPostfix = "mirrored";
5736 MESSAGE("gp_Rotation");
5737 groupPostfix = "rotated";
5739 case gp_Translation:
5740 MESSAGE("gp_Translation");
5741 groupPostfix = "translated";
5744 MESSAGE("gp_Scale");
5745 groupPostfix = "scaled";
5747 case gp_CompoundTrsf: // different scale by axis
5748 MESSAGE("gp_CompoundTrsf");
5749 groupPostfix = "scaled";
5753 needReverse = false;
5754 groupPostfix = "transformed";
5757 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5758 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5759 SMESHDS_Mesh* aMesh = GetMeshDS();
5762 // map old node to new one
5763 TNodeNodeMap nodeMap;
5765 // elements sharing moved nodes; those of them which have all
5766 // nodes mirrored but are not in theElems are to be reversed
5767 TIDSortedElemSet inverseElemSet;
5769 // source elements for each generated one
5770 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5772 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5773 TIDSortedElemSet orphanNode;
5775 if ( theElems.empty() ) // transform the whole mesh
5778 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5779 while ( eIt->more() ) theElems.insert( eIt->next() );
5781 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5782 while ( nIt->more() )
5784 const SMDS_MeshNode* node = nIt->next();
5785 if ( node->NbInverseElements() == 0)
5786 orphanNode.insert( node );
5790 // loop on elements to transform nodes : first orphan nodes then elems
5791 TIDSortedElemSet::iterator itElem;
5792 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5793 for (int i=0; i<2; i++)
5794 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5795 const SMDS_MeshElement* elem = *itElem;
5799 // loop on elem nodes
5800 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5801 while ( itN->more() ) {
5803 const SMDS_MeshNode* node = cast2Node( itN->next() );
5804 // check if a node has been already transformed
5805 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5806 nodeMap.insert( make_pair ( node, node ));
5807 if ( !n2n_isnew.second )
5811 coord[0] = node->X();
5812 coord[1] = node->Y();
5813 coord[2] = node->Z();
5814 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5815 if ( theTargetMesh ) {
5816 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5817 n2n_isnew.first->second = newNode;
5818 myLastCreatedNodes.Append(newNode);
5819 srcNodes.Append( node );
5821 else if ( theCopy ) {
5822 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5823 n2n_isnew.first->second = newNode;
5824 myLastCreatedNodes.Append(newNode);
5825 srcNodes.Append( node );
5828 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5829 // node position on shape becomes invalid
5830 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5831 ( SMDS_SpacePosition::originSpacePosition() );
5834 // keep inverse elements
5835 if ( !theCopy && !theTargetMesh && needReverse ) {
5836 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5837 while ( invElemIt->more() ) {
5838 const SMDS_MeshElement* iel = invElemIt->next();
5839 inverseElemSet.insert( iel );
5845 // either create new elements or reverse mirrored ones
5846 if ( !theCopy && !needReverse && !theTargetMesh )
5849 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5850 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5851 theElems.insert( *invElemIt );
5853 // Replicate or reverse elements
5855 std::vector<int> iForw;
5856 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5858 const SMDS_MeshElement* elem = *itElem;
5859 if ( !elem ) continue;
5861 SMDSAbs_GeometryType geomType = elem->GetGeomType();
5862 int nbNodes = elem->NbNodes();
5863 if ( geomType == SMDSGeom_NONE ) continue; // node
5865 switch ( geomType ) {
5867 case SMDSGeom_POLYGON: // ---------------------- polygon
5869 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5871 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5872 while (itN->more()) {
5873 const SMDS_MeshNode* node =
5874 static_cast<const SMDS_MeshNode*>(itN->next());
5875 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5876 if (nodeMapIt == nodeMap.end())
5877 break; // not all nodes transformed
5879 // reverse mirrored faces and volumes
5880 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5882 poly_nodes[iNode] = (*nodeMapIt).second;
5886 if ( iNode != nbNodes )
5887 continue; // not all nodes transformed
5889 if ( theTargetMesh ) {
5890 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5891 srcElems.Append( elem );
5893 else if ( theCopy ) {
5894 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5895 srcElems.Append( elem );
5898 aMesh->ChangePolygonNodes(elem, poly_nodes);
5903 case SMDSGeom_POLYHEDRA: // ------------------ polyhedral volume
5905 const SMDS_VtkVolume* aPolyedre =
5906 dynamic_cast<const SMDS_VtkVolume*>( elem );
5908 MESSAGE("Warning: bad volumic element");
5912 vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5913 vector<int> quantities; quantities.reserve( nbNodes );
5915 bool allTransformed = true;
5916 int nbFaces = aPolyedre->NbFaces();
5917 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5918 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5919 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5920 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5921 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5922 if (nodeMapIt == nodeMap.end()) {
5923 allTransformed = false; // not all nodes transformed
5925 poly_nodes.push_back((*nodeMapIt).second);
5927 if ( needReverse && allTransformed )
5928 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5930 quantities.push_back(nbFaceNodes);
5932 if ( !allTransformed )
5933 continue; // not all nodes transformed
5935 if ( theTargetMesh ) {
5936 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5937 srcElems.Append( elem );
5939 else if ( theCopy ) {
5940 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5941 srcElems.Append( elem );
5944 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5949 case SMDSGeom_BALL: // -------------------- Ball
5951 if ( !theCopy && !theTargetMesh ) continue;
5953 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
5954 if (nodeMapIt == nodeMap.end())
5955 continue; // not all nodes transformed
5957 double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
5958 if ( theTargetMesh ) {
5959 myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
5960 srcElems.Append( elem );
5963 myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
5964 srcElems.Append( elem );
5969 default: // ----------------------- Regular elements
5971 while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5972 const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5973 const std::vector<int>& i = needReverse ? iRev : iForw;
5975 // find transformed nodes
5976 vector<const SMDS_MeshNode*> nodes(nbNodes);
5978 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5979 while ( itN->more() ) {
5980 const SMDS_MeshNode* node =
5981 static_cast<const SMDS_MeshNode*>( itN->next() );
5982 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5983 if ( nodeMapIt == nodeMap.end() )
5984 break; // not all nodes transformed
5985 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5987 if ( iNode != nbNodes )
5988 continue; // not all nodes transformed
5990 if ( theTargetMesh ) {
5991 if ( SMDS_MeshElement* copy =
5992 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5993 myLastCreatedElems.Append( copy );
5994 srcElems.Append( elem );
5997 else if ( theCopy ) {
5998 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5999 srcElems.Append( elem );
6002 // reverse element as it was reversed by transformation
6004 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6006 } // switch ( geomType )
6008 } // loop on elements
6010 PGroupIDs newGroupIDs;
6012 if ( ( theMakeGroups && theCopy ) ||
6013 ( theMakeGroups && theTargetMesh ) )
6014 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
6019 //=======================================================================
6021 * \brief Create groups of elements made during transformation
6022 * \param nodeGens - nodes making corresponding myLastCreatedNodes
6023 * \param elemGens - elements making corresponding myLastCreatedElems
6024 * \param postfix - to append to names of new groups
6026 //=======================================================================
6028 SMESH_MeshEditor::PGroupIDs
6029 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6030 const SMESH_SequenceOfElemPtr& elemGens,
6031 const std::string& postfix,
6032 SMESH_Mesh* targetMesh)
6034 PGroupIDs newGroupIDs( new list<int> );
6035 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6037 // Sort existing groups by types and collect their names
6039 // to store an old group and a generated new ones
6041 using boost::make_tuple;
6042 typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
6043 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6044 vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6046 set< string > groupNames;
6048 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6049 if ( !groupIt->more() ) return newGroupIDs;
6051 int newGroupID = mesh->GetGroupIds().back()+1;
6052 while ( groupIt->more() )
6054 SMESH_Group * group = groupIt->next();
6055 if ( !group ) continue;
6056 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6057 if ( !groupDS || groupDS->IsEmpty() ) continue;
6058 groupNames.insert ( group->GetName() );
6059 groupDS->SetStoreName( group->GetName() );
6060 const SMDSAbs_ElementType type = groupDS->GetType();
6061 SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6062 SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6063 groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
6064 orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
6067 // Loop on nodes and elements to add them in new groups
6069 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6071 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6072 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6073 if ( gens.Length() != elems.Length() )
6074 throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
6076 // loop on created elements
6077 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6079 const SMDS_MeshElement* sourceElem = gens( iElem );
6080 if ( !sourceElem ) {
6081 MESSAGE("generateGroups(): NULL source element");
6084 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6085 if ( groupsOldNew.empty() ) { // no groups of this type at all
6086 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6087 ++iElem; // skip all elements made by sourceElem
6090 // collect all elements made by the iElem-th sourceElem
6091 list< const SMDS_MeshElement* > resultElems;
6092 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6093 if ( resElem != sourceElem )
6094 resultElems.push_back( resElem );
6095 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6096 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6097 if ( resElem != sourceElem )
6098 resultElems.push_back( resElem );
6100 // there must be a top element
6101 const SMDS_MeshElement* topElem = 0;
6104 topElem = resultElems.back();
6105 resultElems.pop_back();
6109 list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6110 for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6111 if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6113 topElem = *resElemIt;
6114 resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt
6119 // add resultElems to groups originted from ones the sourceElem belongs to
6120 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6121 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6123 SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6124 if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6126 // fill in a new group
6127 SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6128 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6129 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6130 newGroup.Add( *resElemIt );
6132 // fill a "top" group
6135 SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6136 newTopGroup.Add( topElem );
6140 } // loop on created elements
6141 }// loop on nodes and elements
6143 // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6145 list<int> topGrouIds;
6146 for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6148 SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>();
6149 SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6150 orderedOldNewGroups[i]->get<2>() };
6151 const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
6152 for ( int is2nd = 0; is2nd < 2; ++is2nd )
6154 SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6155 if ( newGroupDS->IsEmpty() )
6157 mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6162 newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6165 const bool isTop = ( nbNewGroups == 2 &&
6166 newGroupDS->GetType() == oldGroupDS->GetType() &&
6169 string name = oldGroupDS->GetStoreName();
6170 if ( !targetMesh ) {
6171 string suffix = ( isTop ? "top": postfix.c_str() );
6175 while ( !groupNames.insert( name ).second ) // name exists
6176 name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6181 newGroupDS->SetStoreName( name.c_str() );
6183 // make a SMESH_Groups
6184 mesh->AddGroup( newGroupDS );
6186 topGrouIds.push_back( newGroupDS->GetID() );
6188 newGroupIDs->push_back( newGroupDS->GetID() );
6192 newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6197 //================================================================================
6199 * \brief Return list of group of nodes close to each other within theTolerance
6200 * Search among theNodes or in the whole mesh if theNodes is empty using
6201 * an Octree algorithm
6203 //================================================================================
6205 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6206 const double theTolerance,
6207 TListOfListOfNodes & theGroupsOfNodes)
6209 myLastCreatedElems.Clear();
6210 myLastCreatedNodes.Clear();
6212 if ( theNodes.empty() )
6213 { // get all nodes in the mesh
6214 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6215 while ( nIt->more() )
6216 theNodes.insert( theNodes.end(),nIt->next());
6219 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6222 //=======================================================================
6223 //function : SimplifyFace
6225 //=======================================================================
6227 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
6228 vector<const SMDS_MeshNode *>& poly_nodes,
6229 vector<int>& quantities) const
6231 int nbNodes = faceNodes.size();
6236 set<const SMDS_MeshNode*> nodeSet;
6238 // get simple seq of nodes
6239 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6240 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6241 int iSimple = 0, nbUnique = 0;
6243 simpleNodes[iSimple++] = faceNodes[0];
6245 for (int iCur = 1; iCur < nbNodes; iCur++) {
6246 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6247 simpleNodes[iSimple++] = faceNodes[iCur];
6248 if (nodeSet.insert( faceNodes[iCur] ).second)
6252 int nbSimple = iSimple;
6253 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6263 bool foundLoop = (nbSimple > nbUnique);
6266 set<const SMDS_MeshNode*> loopSet;
6267 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6268 const SMDS_MeshNode* n = simpleNodes[iSimple];
6269 if (!loopSet.insert( n ).second) {
6273 int iC = 0, curLast = iSimple;
6274 for (; iC < curLast; iC++) {
6275 if (simpleNodes[iC] == n) break;
6277 int loopLen = curLast - iC;
6279 // create sub-element
6281 quantities.push_back(loopLen);
6282 for (; iC < curLast; iC++) {
6283 poly_nodes.push_back(simpleNodes[iC]);
6286 // shift the rest nodes (place from the first loop position)
6287 for (iC = curLast + 1; iC < nbSimple; iC++) {
6288 simpleNodes[iC - loopLen] = simpleNodes[iC];
6290 nbSimple -= loopLen;
6293 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6294 } // while (foundLoop)
6298 quantities.push_back(iSimple);
6299 for (int i = 0; i < iSimple; i++)
6300 poly_nodes.push_back(simpleNodes[i]);
6306 //=======================================================================
6307 //function : MergeNodes
6308 //purpose : In each group, the cdr of nodes are substituted by the first one
6310 //=======================================================================
6312 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6314 MESSAGE("MergeNodes");
6315 myLastCreatedElems.Clear();
6316 myLastCreatedNodes.Clear();
6318 SMESHDS_Mesh* aMesh = GetMeshDS();
6320 TNodeNodeMap nodeNodeMap; // node to replace - new node
6321 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6322 list< int > rmElemIds, rmNodeIds;
6324 // Fill nodeNodeMap and elems
6326 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6327 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6328 list<const SMDS_MeshNode*>& nodes = *grIt;
6329 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6330 const SMDS_MeshNode* nToKeep = *nIt;
6331 //MESSAGE("node to keep " << nToKeep->GetID());
6332 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6333 const SMDS_MeshNode* nToRemove = *nIt;
6334 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6335 if ( nToRemove != nToKeep ) {
6336 //MESSAGE(" node to remove " << nToRemove->GetID());
6337 rmNodeIds.push_back( nToRemove->GetID() );
6338 AddToSameGroups( nToKeep, nToRemove, aMesh );
6339 // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
6340 // after MergeNodes() w/o creating node in place of merged ones.
6341 const SMDS_PositionPtr& pos = nToRemove->GetPosition();
6342 if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
6343 if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
6344 sm->SetIsAlwaysComputed( true );
6347 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6348 while ( invElemIt->more() ) {
6349 const SMDS_MeshElement* elem = invElemIt->next();
6354 // Change element nodes or remove an element
6356 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6357 for ( ; eIt != elems.end(); eIt++ ) {
6358 const SMDS_MeshElement* elem = *eIt;
6359 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
6360 int nbNodes = elem->NbNodes();
6361 int aShapeId = FindShape( elem );
6363 set<const SMDS_MeshNode*> nodeSet;
6364 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6365 int iUnique = 0, iCur = 0, nbRepl = 0;
6366 vector<int> iRepl( nbNodes );
6368 // get new seq of nodes
6369 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6370 while ( itN->more() ) {
6371 const SMDS_MeshNode* n =
6372 static_cast<const SMDS_MeshNode*>( itN->next() );
6374 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6375 if ( nnIt != nodeNodeMap.end() ) { // n sticks
6377 // BUG 0020185: begin
6379 bool stopRecur = false;
6380 set<const SMDS_MeshNode*> nodesRecur;
6381 nodesRecur.insert(n);
6382 while (!stopRecur) {
6383 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6384 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6385 n = (*nnIt_i).second;
6386 if (!nodesRecur.insert(n).second) {
6387 // error: recursive dependancy
6397 curNodes[ iCur ] = n;
6398 bool isUnique = nodeSet.insert( n ).second;
6400 uniqueNodes[ iUnique++ ] = n;
6402 iRepl[ nbRepl++ ] = iCur;
6406 // Analyse element topology after replacement
6409 int nbUniqueNodes = nodeSet.size();
6410 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
6411 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6412 // Polygons and Polyhedral volumes
6413 if (elem->IsPoly()) {
6415 if (elem->GetType() == SMDSAbs_Face) {
6417 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6419 for (; inode < nbNodes; inode++) {
6420 face_nodes[inode] = curNodes[inode];
6423 vector<const SMDS_MeshNode *> polygons_nodes;
6424 vector<int> quantities;
6425 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6428 for (int iface = 0; iface < nbNew; iface++) {
6429 int nbNodes = quantities[iface];
6430 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6431 for (int ii = 0; ii < nbNodes; ii++, inode++) {
6432 poly_nodes[ii] = polygons_nodes[inode];
6434 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6435 myLastCreatedElems.Append(newElem);
6437 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6440 MESSAGE("ChangeElementNodes MergeNodes Polygon");
6441 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6442 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
6444 if (nbNew > 0) quid = nbNew - 1;
6445 vector<int> newquant(quantities.begin()+quid, quantities.end());
6446 const SMDS_MeshElement* newElem = 0;
6447 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
6448 myLastCreatedElems.Append(newElem);
6449 if ( aShapeId && newElem )
6450 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6451 rmElemIds.push_back(elem->GetID());
6454 rmElemIds.push_back(elem->GetID());
6458 else if (elem->GetType() == SMDSAbs_Volume) {
6459 // Polyhedral volume
6460 if (nbUniqueNodes < 4) {
6461 rmElemIds.push_back(elem->GetID());
6464 // each face has to be analyzed in order to check volume validity
6465 const SMDS_VtkVolume* aPolyedre =
6466 dynamic_cast<const SMDS_VtkVolume*>( elem );
6468 int nbFaces = aPolyedre->NbFaces();
6470 vector<const SMDS_MeshNode *> poly_nodes;
6471 vector<int> quantities;
6473 for (int iface = 1; iface <= nbFaces; iface++) {
6474 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6475 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6477 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6478 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6479 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6480 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6481 faceNode = (*nnIt).second;
6483 faceNodes[inode - 1] = faceNode;
6486 SimplifyFace(faceNodes, poly_nodes, quantities);
6489 if (quantities.size() > 3) {
6490 // to be done: remove coincident faces
6493 if (quantities.size() > 3)
6495 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
6496 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6497 const SMDS_MeshElement* newElem = 0;
6498 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6499 myLastCreatedElems.Append(newElem);
6500 if ( aShapeId && newElem )
6501 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6502 rmElemIds.push_back(elem->GetID());
6506 rmElemIds.push_back(elem->GetID());
6517 // TODO not all the possible cases are solved. Find something more generic?
6518 switch ( nbNodes ) {
6519 case 2: ///////////////////////////////////// EDGE
6520 isOk = false; break;
6521 case 3: ///////////////////////////////////// TRIANGLE
6522 isOk = false; break;
6524 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6526 else { //////////////////////////////////// QUADRANGLE
6527 if ( nbUniqueNodes < 3 )
6529 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6530 isOk = false; // opposite nodes stick
6531 //MESSAGE("isOk " << isOk);
6534 case 6: ///////////////////////////////////// PENTAHEDRON
6535 if ( nbUniqueNodes == 4 ) {
6536 // ---------------------------------> tetrahedron
6538 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6539 // all top nodes stick: reverse a bottom
6540 uniqueNodes[ 0 ] = curNodes [ 1 ];
6541 uniqueNodes[ 1 ] = curNodes [ 0 ];
6543 else if (nbRepl == 3 &&
6544 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6545 // all bottom nodes stick: set a top before
6546 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6547 uniqueNodes[ 0 ] = curNodes [ 3 ];
6548 uniqueNodes[ 1 ] = curNodes [ 4 ];
6549 uniqueNodes[ 2 ] = curNodes [ 5 ];
6551 else if (nbRepl == 4 &&
6552 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6553 // a lateral face turns into a line: reverse a bottom
6554 uniqueNodes[ 0 ] = curNodes [ 1 ];
6555 uniqueNodes[ 1 ] = curNodes [ 0 ];
6560 else if ( nbUniqueNodes == 5 ) {
6561 // PENTAHEDRON --------------------> 2 tetrahedrons
6562 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6563 // a bottom node sticks with a linked top one
6565 SMDS_MeshElement* newElem =
6566 aMesh->AddVolume(curNodes[ 3 ],
6569 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6570 myLastCreatedElems.Append(newElem);
6572 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6573 // 2. : reverse a bottom
6574 uniqueNodes[ 0 ] = curNodes [ 1 ];
6575 uniqueNodes[ 1 ] = curNodes [ 0 ];
6585 if(elem->IsQuadratic()) { // Quadratic quadrangle
6597 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
6600 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
6602 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6603 uniqueNodes[0] = curNodes[0];
6604 uniqueNodes[1] = curNodes[2];
6605 uniqueNodes[2] = curNodes[3];
6606 uniqueNodes[3] = curNodes[5];
6607 uniqueNodes[4] = curNodes[6];
6608 uniqueNodes[5] = curNodes[7];
6611 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6612 uniqueNodes[0] = curNodes[0];
6613 uniqueNodes[1] = curNodes[1];
6614 uniqueNodes[2] = curNodes[2];
6615 uniqueNodes[3] = curNodes[4];
6616 uniqueNodes[4] = curNodes[5];
6617 uniqueNodes[5] = curNodes[6];
6620 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6621 uniqueNodes[0] = curNodes[1];
6622 uniqueNodes[1] = curNodes[2];
6623 uniqueNodes[2] = curNodes[3];
6624 uniqueNodes[3] = curNodes[5];
6625 uniqueNodes[4] = curNodes[6];
6626 uniqueNodes[5] = curNodes[0];
6629 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6630 uniqueNodes[0] = curNodes[0];
6631 uniqueNodes[1] = curNodes[1];
6632 uniqueNodes[2] = curNodes[3];
6633 uniqueNodes[3] = curNodes[4];
6634 uniqueNodes[4] = curNodes[6];
6635 uniqueNodes[5] = curNodes[7];
6638 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6639 uniqueNodes[0] = curNodes[0];
6640 uniqueNodes[1] = curNodes[2];
6641 uniqueNodes[2] = curNodes[3];
6642 uniqueNodes[3] = curNodes[1];
6643 uniqueNodes[4] = curNodes[6];
6644 uniqueNodes[5] = curNodes[7];
6647 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6648 uniqueNodes[0] = curNodes[0];
6649 uniqueNodes[1] = curNodes[1];
6650 uniqueNodes[2] = curNodes[2];
6651 uniqueNodes[3] = curNodes[4];
6652 uniqueNodes[4] = curNodes[5];
6653 uniqueNodes[5] = curNodes[7];
6656 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6657 uniqueNodes[0] = curNodes[0];
6658 uniqueNodes[1] = curNodes[1];
6659 uniqueNodes[2] = curNodes[3];
6660 uniqueNodes[3] = curNodes[4];
6661 uniqueNodes[4] = curNodes[2];
6662 uniqueNodes[5] = curNodes[7];
6665 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6666 uniqueNodes[0] = curNodes[0];
6667 uniqueNodes[1] = curNodes[1];
6668 uniqueNodes[2] = curNodes[2];
6669 uniqueNodes[3] = curNodes[4];
6670 uniqueNodes[4] = curNodes[5];
6671 uniqueNodes[5] = curNodes[3];
6676 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
6679 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
6683 //////////////////////////////////// HEXAHEDRON
6685 SMDS_VolumeTool hexa (elem);
6686 hexa.SetExternalNormal();
6687 if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
6688 //////////////////////// HEX ---> 1 tetrahedron
6689 for ( int iFace = 0; iFace < 6; iFace++ ) {
6690 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6691 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6692 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6693 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6694 // one face turns into a point ...
6695 int iOppFace = hexa.GetOppFaceIndex( iFace );
6696 ind = hexa.GetFaceNodesIndices( iOppFace );
6698 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6699 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6702 if ( nbStick == 1 ) {
6703 // ... and the opposite one - into a triangle.
6705 ind = hexa.GetFaceNodesIndices( iFace );
6706 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6713 else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
6714 //////////////////////// HEX ---> 1 prism
6715 int nbTria = 0, iTria[3];
6716 const int *ind; // indices of face nodes
6717 // look for triangular faces
6718 for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
6719 ind = hexa.GetFaceNodesIndices( iFace );
6720 TIDSortedNodeSet faceNodes;
6721 for ( iCur = 0; iCur < 4; iCur++ )
6722 faceNodes.insert( curNodes[ind[iCur]] );
6723 if ( faceNodes.size() == 3 )
6724 iTria[ nbTria++ ] = iFace;
6726 // check if triangles are opposite
6727 if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
6730 // set nodes of the bottom triangle
6731 ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
6733 for ( iCur = 0; iCur < 4; iCur++ )
6734 if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
6735 indB.push_back( ind[iCur] );
6736 if ( !hexa.IsForward() )
6737 std::swap( indB[0], indB[2] );
6738 for ( iCur = 0; iCur < 3; iCur++ )
6739 uniqueNodes[ iCur ] = curNodes[indB[iCur]];
6740 // set nodes of the top triangle
6741 const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
6742 for ( iCur = 0; iCur < 3; ++iCur )
6743 for ( int j = 0; j < 4; ++j )
6744 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
6746 uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
6752 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6753 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6754 for ( int iFace = 0; iFace < 6; iFace++ ) {
6755 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6756 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6757 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6758 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6759 // one face turns into a point ...
6760 int iOppFace = hexa.GetOppFaceIndex( iFace );
6761 ind = hexa.GetFaceNodesIndices( iOppFace );
6763 iUnique = 2; // reverse a tetrahedron 1 bottom
6764 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6765 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6767 else if ( iUnique >= 0 )
6768 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6770 if ( nbStick == 0 ) {
6771 // ... and the opposite one is a quadrangle
6773 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6774 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6777 SMDS_MeshElement* newElem =
6778 aMesh->AddVolume(curNodes[ind[ 0 ]],
6781 curNodes[indTop[ 0 ]]);
6782 myLastCreatedElems.Append(newElem);
6784 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6791 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6792 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6793 // find indices of quad and tri faces
6794 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6795 for ( iFace = 0; iFace < 6; iFace++ ) {
6796 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6798 for ( iCur = 0; iCur < 4; iCur++ )
6799 nodeSet.insert( curNodes[ind[ iCur ]] );
6800 nbUniqueNodes = nodeSet.size();
6801 if ( nbUniqueNodes == 3 )
6802 iTriFace[ nbTri++ ] = iFace;
6803 else if ( nbUniqueNodes == 4 )
6804 iQuadFace[ nbQuad++ ] = iFace;
6806 if (nbQuad == 2 && nbTri == 4 &&
6807 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6808 // 2 opposite quadrangles stuck with a diagonal;
6809 // sample groups of merged indices: (0-4)(2-6)
6810 // --------------------------------------------> 2 tetrahedrons
6811 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6812 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6813 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6814 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6815 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6816 // stuck with 0-2 diagonal
6824 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6825 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6826 // stuck with 1-3 diagonal
6838 uniqueNodes[ 0 ] = curNodes [ i0 ];
6839 uniqueNodes[ 1 ] = curNodes [ i1d ];
6840 uniqueNodes[ 2 ] = curNodes [ i3d ];
6841 uniqueNodes[ 3 ] = curNodes [ i0t ];
6844 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6848 myLastCreatedElems.Append(newElem);
6850 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6853 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6854 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6855 // --------------------------------------------> prism
6856 // find 2 opposite triangles
6858 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6859 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6860 // find indices of kept and replaced nodes
6861 // and fill unique nodes of 2 opposite triangles
6862 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6863 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6864 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6865 // fill unique nodes
6868 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6869 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
6870 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6872 // iCur of a linked node of the opposite face (make normals co-directed):
6873 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6874 // check that correspondent corners of triangles are linked
6875 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6878 uniqueNodes[ iUnique ] = n;
6879 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6888 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6891 MESSAGE("MergeNodes() removes hexahedron "<< elem);
6898 } // switch ( nbNodes )
6900 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6902 if ( isOk ) { // the elem remains valid after sticking nodes
6903 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
6905 // Change nodes of polyedre
6906 const SMDS_VtkVolume* aPolyedre =
6907 dynamic_cast<const SMDS_VtkVolume*>( elem );
6909 int nbFaces = aPolyedre->NbFaces();
6911 vector<const SMDS_MeshNode *> poly_nodes;
6912 vector<int> quantities (nbFaces);
6914 for (int iface = 1; iface <= nbFaces; iface++) {
6915 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6916 quantities[iface - 1] = nbFaceNodes;
6918 for (inode = 1; inode <= nbFaceNodes; inode++) {
6919 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6921 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6922 if (nnIt != nodeNodeMap.end()) { // curNode sticks
6923 curNode = (*nnIt).second;
6925 poly_nodes.push_back(curNode);
6928 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6931 else // replace non-polyhedron elements
6933 const SMDSAbs_ElementType etyp = elem->GetType();
6934 const int elemId = elem->GetID();
6935 const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
6936 uniqueNodes.resize(nbUniqueNodes);
6938 SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
6940 aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
6941 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
6942 if ( sm && newElem )
6943 sm->AddElement( newElem );
6944 if ( elem != newElem )
6945 ReplaceElemInGroups( elem, newElem, aMesh );
6949 // Remove invalid regular element or invalid polygon
6950 rmElemIds.push_back( elem->GetID() );
6953 } // loop on elements
6955 // Remove bad elements, then equal nodes (order important)
6957 Remove( rmElemIds, false );
6958 Remove( rmNodeIds, true );
6963 // ========================================================
6964 // class : SortableElement
6965 // purpose : allow sorting elements basing on their nodes
6966 // ========================================================
6967 class SortableElement : public set <const SMDS_MeshElement*>
6971 SortableElement( const SMDS_MeshElement* theElem )
6974 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6975 while ( nodeIt->more() )
6976 this->insert( nodeIt->next() );
6979 const SMDS_MeshElement* Get() const
6982 void Set(const SMDS_MeshElement* e) const
6987 mutable const SMDS_MeshElement* myElem;
6990 //=======================================================================
6991 //function : FindEqualElements
6992 //purpose : Return list of group of elements built on the same nodes.
6993 // Search among theElements or in the whole mesh if theElements is empty
6994 //=======================================================================
6996 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements,
6997 TListOfListOfElementsID & theGroupsOfElementsID)
6999 myLastCreatedElems.Clear();
7000 myLastCreatedNodes.Clear();
7002 typedef map< SortableElement, int > TMapOfNodeSet;
7003 typedef list<int> TGroupOfElems;
7005 if ( theElements.empty() )
7006 { // get all elements in the mesh
7007 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7008 while ( eIt->more() )
7009 theElements.insert( theElements.end(), eIt->next());
7012 vector< TGroupOfElems > arrayOfGroups;
7013 TGroupOfElems groupOfElems;
7014 TMapOfNodeSet mapOfNodeSet;
7016 TIDSortedElemSet::iterator elemIt = theElements.begin();
7017 for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
7018 const SMDS_MeshElement* curElem = *elemIt;
7019 SortableElement SE(curElem);
7022 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7023 if( !(pp.second) ) {
7024 TMapOfNodeSet::iterator& itSE = pp.first;
7025 ind = (*itSE).second;
7026 arrayOfGroups[ind].push_back(curElem->GetID());
7029 groupOfElems.clear();
7030 groupOfElems.push_back(curElem->GetID());
7031 arrayOfGroups.push_back(groupOfElems);
7036 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7037 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7038 groupOfElems = *groupIt;
7039 if ( groupOfElems.size() > 1 ) {
7040 groupOfElems.sort();
7041 theGroupsOfElementsID.push_back(groupOfElems);
7046 //=======================================================================
7047 //function : MergeElements
7048 //purpose : In each given group, substitute all elements by the first one.
7049 //=======================================================================
7051 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7053 myLastCreatedElems.Clear();
7054 myLastCreatedNodes.Clear();
7056 typedef list<int> TListOfIDs;
7057 TListOfIDs rmElemIds; // IDs of elems to remove
7059 SMESHDS_Mesh* aMesh = GetMeshDS();
7061 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7062 while ( groupsIt != theGroupsOfElementsID.end() ) {
7063 TListOfIDs& aGroupOfElemID = *groupsIt;
7064 aGroupOfElemID.sort();
7065 int elemIDToKeep = aGroupOfElemID.front();
7066 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7067 aGroupOfElemID.pop_front();
7068 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7069 while ( idIt != aGroupOfElemID.end() ) {
7070 int elemIDToRemove = *idIt;
7071 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7072 // add the kept element in groups of removed one (PAL15188)
7073 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7074 rmElemIds.push_back( elemIDToRemove );
7080 Remove( rmElemIds, false );
7083 //=======================================================================
7084 //function : MergeEqualElements
7085 //purpose : Remove all but one of elements built on the same nodes.
7086 //=======================================================================
7088 void SMESH_MeshEditor::MergeEqualElements()
7090 TIDSortedElemSet aMeshElements; /* empty input ==
7091 to merge equal elements in the whole mesh */
7092 TListOfListOfElementsID aGroupsOfElementsID;
7093 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7094 MergeElements(aGroupsOfElementsID);
7097 //=======================================================================
7098 //function : findAdjacentFace
7100 //=======================================================================
7102 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7103 const SMDS_MeshNode* n2,
7104 const SMDS_MeshElement* elem)
7106 TIDSortedElemSet elemSet, avoidSet;
7108 avoidSet.insert ( elem );
7109 return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
7112 //=======================================================================
7113 //function : FindFreeBorder
7115 //=======================================================================
7117 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7119 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7120 const SMDS_MeshNode* theSecondNode,
7121 const SMDS_MeshNode* theLastNode,
7122 list< const SMDS_MeshNode* > & theNodes,
7123 list< const SMDS_MeshElement* >& theFaces)
7125 if ( !theFirstNode || !theSecondNode )
7127 // find border face between theFirstNode and theSecondNode
7128 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7132 theFaces.push_back( curElem );
7133 theNodes.push_back( theFirstNode );
7134 theNodes.push_back( theSecondNode );
7136 //vector<const SMDS_MeshNode*> nodes;
7137 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7138 TIDSortedElemSet foundElems;
7139 bool needTheLast = ( theLastNode != 0 );
7141 while ( nStart != theLastNode ) {
7142 if ( nStart == theFirstNode )
7143 return !needTheLast;
7145 // find all free border faces sharing form nStart
7147 list< const SMDS_MeshElement* > curElemList;
7148 list< const SMDS_MeshNode* > nStartList;
7149 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7150 while ( invElemIt->more() ) {
7151 const SMDS_MeshElement* e = invElemIt->next();
7152 if ( e == curElem || foundElems.insert( e ).second ) {
7154 int iNode = 0, nbNodes = e->NbNodes();
7155 //const SMDS_MeshNode* nodes[nbNodes+1];
7156 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7158 if(e->IsQuadratic()) {
7159 const SMDS_VtkFace* F =
7160 dynamic_cast<const SMDS_VtkFace*>(e);
7161 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7162 // use special nodes iterator
7163 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7164 while( anIter->more() ) {
7165 nodes[ iNode++ ] = cast2Node(anIter->next());
7169 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7170 while ( nIt->more() )
7171 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7173 nodes[ iNode ] = nodes[ 0 ];
7175 for ( iNode = 0; iNode < nbNodes; iNode++ )
7176 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7177 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7178 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7180 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7181 curElemList.push_back( e );
7185 // analyse the found
7187 int nbNewBorders = curElemList.size();
7188 if ( nbNewBorders == 0 ) {
7189 // no free border furthermore
7190 return !needTheLast;
7192 else if ( nbNewBorders == 1 ) {
7193 // one more element found
7195 nStart = nStartList.front();
7196 curElem = curElemList.front();
7197 theFaces.push_back( curElem );
7198 theNodes.push_back( nStart );
7201 // several continuations found
7202 list< const SMDS_MeshElement* >::iterator curElemIt;
7203 list< const SMDS_MeshNode* >::iterator nStartIt;
7204 // check if one of them reached the last node
7205 if ( needTheLast ) {
7206 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7207 curElemIt!= curElemList.end();
7208 curElemIt++, nStartIt++ )
7209 if ( *nStartIt == theLastNode ) {
7210 theFaces.push_back( *curElemIt );
7211 theNodes.push_back( *nStartIt );
7215 // find the best free border by the continuations
7216 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7217 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7218 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7219 curElemIt!= curElemList.end();
7220 curElemIt++, nStartIt++ )
7222 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7223 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7224 // find one more free border
7225 if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7229 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7230 // choice: clear a worse one
7231 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7232 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7233 contNodes[ iWorse ].clear();
7234 contFaces[ iWorse ].clear();
7237 if ( contNodes[0].empty() && contNodes[1].empty() )
7240 // append the best free border
7241 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7242 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7243 theNodes.pop_back(); // remove nIgnore
7244 theNodes.pop_back(); // remove nStart
7245 theFaces.pop_back(); // remove curElem
7246 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7247 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7248 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7249 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7252 } // several continuations found
7253 } // while ( nStart != theLastNode )
7258 //=======================================================================
7259 //function : CheckFreeBorderNodes
7260 //purpose : Return true if the tree nodes are on a free border
7261 //=======================================================================
7263 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7264 const SMDS_MeshNode* theNode2,
7265 const SMDS_MeshNode* theNode3)
7267 list< const SMDS_MeshNode* > nodes;
7268 list< const SMDS_MeshElement* > faces;
7269 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7272 //=======================================================================
7273 //function : SewFreeBorder
7275 //=======================================================================
7277 SMESH_MeshEditor::Sew_Error
7278 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7279 const SMDS_MeshNode* theBordSecondNode,
7280 const SMDS_MeshNode* theBordLastNode,
7281 const SMDS_MeshNode* theSideFirstNode,
7282 const SMDS_MeshNode* theSideSecondNode,
7283 const SMDS_MeshNode* theSideThirdNode,
7284 const bool theSideIsFreeBorder,
7285 const bool toCreatePolygons,
7286 const bool toCreatePolyedrs)
7288 myLastCreatedElems.Clear();
7289 myLastCreatedNodes.Clear();
7291 MESSAGE("::SewFreeBorder()");
7292 Sew_Error aResult = SEW_OK;
7294 // ====================================
7295 // find side nodes and elements
7296 // ====================================
7298 list< const SMDS_MeshNode* > nSide[ 2 ];
7299 list< const SMDS_MeshElement* > eSide[ 2 ];
7300 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7301 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7305 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7306 nSide[0], eSide[0])) {
7307 MESSAGE(" Free Border 1 not found " );
7308 aResult = SEW_BORDER1_NOT_FOUND;
7310 if (theSideIsFreeBorder) {
7313 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7314 nSide[1], eSide[1])) {
7315 MESSAGE(" Free Border 2 not found " );
7316 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7319 if ( aResult != SEW_OK )
7322 if (!theSideIsFreeBorder) {
7326 // -------------------------------------------------------------------------
7328 // 1. If nodes to merge are not coincident, move nodes of the free border
7329 // from the coord sys defined by the direction from the first to last
7330 // nodes of the border to the correspondent sys of the side 2
7331 // 2. On the side 2, find the links most co-directed with the correspondent
7332 // links of the free border
7333 // -------------------------------------------------------------------------
7335 // 1. Since sewing may break if there are volumes to split on the side 2,
7336 // we wont move nodes but just compute new coordinates for them
7337 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7338 TNodeXYZMap nBordXYZ;
7339 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7340 list< const SMDS_MeshNode* >::iterator nBordIt;
7342 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7343 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7344 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7345 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7346 double tol2 = 1.e-8;
7347 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7348 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7349 // Need node movement.
7351 // find X and Z axes to create trsf
7352 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7354 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7356 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7359 gp_Ax3 toBordAx( Pb1, Zb, X );
7360 gp_Ax3 fromSideAx( Ps1, Zs, X );
7361 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7363 gp_Trsf toBordSys, fromSide2Sys;
7364 toBordSys.SetTransformation( toBordAx );
7365 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7366 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7369 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7370 const SMDS_MeshNode* n = *nBordIt;
7371 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7372 toBordSys.Transforms( xyz );
7373 fromSide2Sys.Transforms( xyz );
7374 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7378 // just insert nodes XYZ in the nBordXYZ map
7379 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7380 const SMDS_MeshNode* n = *nBordIt;
7381 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7385 // 2. On the side 2, find the links most co-directed with the correspondent
7386 // links of the free border
7388 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7389 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7390 sideNodes.push_back( theSideFirstNode );
7392 bool hasVolumes = false;
7393 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7394 set<long> foundSideLinkIDs, checkedLinkIDs;
7395 SMDS_VolumeTool volume;
7396 //const SMDS_MeshNode* faceNodes[ 4 ];
7398 const SMDS_MeshNode* sideNode;
7399 const SMDS_MeshElement* sideElem;
7400 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7401 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7402 nBordIt = bordNodes.begin();
7404 // border node position and border link direction to compare with
7405 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7406 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7407 // choose next side node by link direction or by closeness to
7408 // the current border node:
7409 bool searchByDir = ( *nBordIt != theBordLastNode );
7411 // find the next node on the Side 2
7413 double maxDot = -DBL_MAX, minDist = DBL_MAX;
7415 checkedLinkIDs.clear();
7416 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7418 // loop on inverse elements of current node (prevSideNode) on the Side 2
7419 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7420 while ( invElemIt->more() )
7422 const SMDS_MeshElement* elem = invElemIt->next();
7423 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7424 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7425 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7426 bool isVolume = volume.Set( elem );
7427 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7428 if ( isVolume ) // --volume
7430 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7431 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7432 if(elem->IsQuadratic()) {
7433 const SMDS_VtkFace* F =
7434 dynamic_cast<const SMDS_VtkFace*>(elem);
7435 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7436 // use special nodes iterator
7437 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7438 while( anIter->more() ) {
7439 nodes[ iNode ] = cast2Node(anIter->next());
7440 if ( nodes[ iNode++ ] == prevSideNode )
7441 iPrevNode = iNode - 1;
7445 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7446 while ( nIt->more() ) {
7447 nodes[ iNode ] = cast2Node( nIt->next() );
7448 if ( nodes[ iNode++ ] == prevSideNode )
7449 iPrevNode = iNode - 1;
7452 // there are 2 links to check
7457 // loop on links, to be precise, on the second node of links
7458 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7459 const SMDS_MeshNode* n = nodes[ iNode ];
7461 if ( !volume.IsLinked( n, prevSideNode ))
7465 if ( iNode ) // a node before prevSideNode
7466 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7467 else // a node after prevSideNode
7468 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7470 // check if this link was already used
7471 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7472 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7473 if (!isJustChecked &&
7474 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7476 // test a link geometrically
7477 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7478 bool linkIsBetter = false;
7479 double dot = 0.0, dist = 0.0;
7480 if ( searchByDir ) { // choose most co-directed link
7481 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7482 linkIsBetter = ( dot > maxDot );
7484 else { // choose link with the node closest to bordPos
7485 dist = ( nextXYZ - bordPos ).SquareModulus();
7486 linkIsBetter = ( dist < minDist );
7488 if ( linkIsBetter ) {
7497 } // loop on inverse elements of prevSideNode
7500 MESSAGE(" Cant find path by links of the Side 2 ");
7501 return SEW_BAD_SIDE_NODES;
7503 sideNodes.push_back( sideNode );
7504 sideElems.push_back( sideElem );
7505 foundSideLinkIDs.insert ( linkID );
7506 prevSideNode = sideNode;
7508 if ( *nBordIt == theBordLastNode )
7509 searchByDir = false;
7511 // find the next border link to compare with
7512 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7513 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7514 // move to next border node if sideNode is before forward border node (bordPos)
7515 while ( *nBordIt != theBordLastNode && !searchByDir ) {
7516 prevBordNode = *nBordIt;
7518 bordPos = nBordXYZ[ *nBordIt ];
7519 bordDir = bordPos - nBordXYZ[ prevBordNode ];
7520 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7524 while ( sideNode != theSideSecondNode );
7526 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7527 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7528 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7530 } // end nodes search on the side 2
7532 // ============================
7533 // sew the border to the side 2
7534 // ============================
7536 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
7537 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7539 TListOfListOfNodes nodeGroupsToMerge;
7540 if ( nbNodes[0] == nbNodes[1] ||
7541 ( theSideIsFreeBorder && !theSideThirdNode)) {
7543 // all nodes are to be merged
7545 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7546 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7547 nIt[0]++, nIt[1]++ )
7549 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7550 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7551 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7556 // insert new nodes into the border and the side to get equal nb of segments
7558 // get normalized parameters of nodes on the borders
7559 //double param[ 2 ][ maxNbNodes ];
7561 param[0] = new double [ maxNbNodes ];
7562 param[1] = new double [ maxNbNodes ];
7564 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7565 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7566 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7567 const SMDS_MeshNode* nPrev = *nIt;
7568 double bordLength = 0;
7569 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7570 const SMDS_MeshNode* nCur = *nIt;
7571 gp_XYZ segment (nCur->X() - nPrev->X(),
7572 nCur->Y() - nPrev->Y(),
7573 nCur->Z() - nPrev->Z());
7574 double segmentLen = segment.Modulus();
7575 bordLength += segmentLen;
7576 param[ iBord ][ iNode ] = bordLength;
7579 // normalize within [0,1]
7580 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7581 param[ iBord ][ iNode ] /= bordLength;
7585 // loop on border segments
7586 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7587 int i[ 2 ] = { 0, 0 };
7588 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7589 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7591 TElemOfNodeListMap insertMap;
7592 TElemOfNodeListMap::iterator insertMapIt;
7594 // key: elem to insert nodes into
7595 // value: 2 nodes to insert between + nodes to be inserted
7597 bool next[ 2 ] = { false, false };
7599 // find min adjacent segment length after sewing
7600 double nextParam = 10., prevParam = 0;
7601 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7602 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7603 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7604 if ( i[ iBord ] > 0 )
7605 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7607 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7608 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7609 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7611 // choose to insert or to merge nodes
7612 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7613 if ( Abs( du ) <= minSegLen * 0.2 ) {
7616 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7617 const SMDS_MeshNode* n0 = *nIt[0];
7618 const SMDS_MeshNode* n1 = *nIt[1];
7619 nodeGroupsToMerge.back().push_back( n1 );
7620 nodeGroupsToMerge.back().push_back( n0 );
7621 // position of node of the border changes due to merge
7622 param[ 0 ][ i[0] ] += du;
7623 // move n1 for the sake of elem shape evaluation during insertion.
7624 // n1 will be removed by MergeNodes() anyway
7625 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7626 next[0] = next[1] = true;
7631 int intoBord = ( du < 0 ) ? 0 : 1;
7632 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7633 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7634 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7635 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7636 if ( intoBord == 1 ) {
7637 // move node of the border to be on a link of elem of the side
7638 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7639 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7640 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7641 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7642 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7644 insertMapIt = insertMap.find( elem );
7645 bool notFound = ( insertMapIt == insertMap.end() );
7646 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7648 // insert into another link of the same element:
7649 // 1. perform insertion into the other link of the elem
7650 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7651 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7652 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7653 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7654 // 2. perform insertion into the link of adjacent faces
7656 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7658 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7662 if (toCreatePolyedrs) {
7663 // perform insertion into the links of adjacent volumes
7664 UpdateVolumes(n12, n22, nodeList);
7666 // 3. find an element appeared on n1 and n2 after the insertion
7667 insertMap.erase( elem );
7668 elem = findAdjacentFace( n1, n2, 0 );
7670 if ( notFound || otherLink ) {
7671 // add element and nodes of the side into the insertMap
7672 insertMapIt = insertMap.insert
7673 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7674 (*insertMapIt).second.push_back( n1 );
7675 (*insertMapIt).second.push_back( n2 );
7677 // add node to be inserted into elem
7678 (*insertMapIt).second.push_back( nIns );
7679 next[ 1 - intoBord ] = true;
7682 // go to the next segment
7683 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7684 if ( next[ iBord ] ) {
7685 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7687 nPrev[ iBord ] = *nIt[ iBord ];
7688 nIt[ iBord ]++; i[ iBord ]++;
7692 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7694 // perform insertion of nodes into elements
7696 for (insertMapIt = insertMap.begin();
7697 insertMapIt != insertMap.end();
7700 const SMDS_MeshElement* elem = (*insertMapIt).first;
7701 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7702 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7703 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7705 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7707 if ( !theSideIsFreeBorder ) {
7708 // look for and insert nodes into the faces adjacent to elem
7710 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7712 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7717 if (toCreatePolyedrs) {
7718 // perform insertion into the links of adjacent volumes
7719 UpdateVolumes(n1, n2, nodeList);
7725 } // end: insert new nodes
7727 MergeNodes ( nodeGroupsToMerge );
7732 //=======================================================================
7733 //function : InsertNodesIntoLink
7734 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7735 // and theBetweenNode2 and split theElement
7736 //=======================================================================
7738 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7739 const SMDS_MeshNode* theBetweenNode1,
7740 const SMDS_MeshNode* theBetweenNode2,
7741 list<const SMDS_MeshNode*>& theNodesToInsert,
7742 const bool toCreatePoly)
7744 if ( theFace->GetType() != SMDSAbs_Face ) return;
7746 // find indices of 2 link nodes and of the rest nodes
7747 int iNode = 0, il1, il2, i3, i4;
7748 il1 = il2 = i3 = i4 = -1;
7749 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7750 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7752 if(theFace->IsQuadratic()) {
7753 const SMDS_VtkFace* F =
7754 dynamic_cast<const SMDS_VtkFace*>(theFace);
7755 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7756 // use special nodes iterator
7757 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7758 while( anIter->more() ) {
7759 const SMDS_MeshNode* n = cast2Node(anIter->next());
7760 if ( n == theBetweenNode1 )
7762 else if ( n == theBetweenNode2 )
7768 nodes[ iNode++ ] = n;
7772 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7773 while ( nodeIt->more() ) {
7774 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7775 if ( n == theBetweenNode1 )
7777 else if ( n == theBetweenNode2 )
7783 nodes[ iNode++ ] = n;
7786 if ( il1 < 0 || il2 < 0 || i3 < 0 )
7789 // arrange link nodes to go one after another regarding the face orientation
7790 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7791 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7796 aNodesToInsert.reverse();
7798 // check that not link nodes of a quadrangles are in good order
7799 int nbFaceNodes = theFace->NbNodes();
7800 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7806 if (toCreatePoly || theFace->IsPoly()) {
7809 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7811 // add nodes of face up to first node of link
7814 if(theFace->IsQuadratic()) {
7815 const SMDS_VtkFace* F =
7816 dynamic_cast<const SMDS_VtkFace*>(theFace);
7817 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7818 // use special nodes iterator
7819 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7820 while( anIter->more() && !isFLN ) {
7821 const SMDS_MeshNode* n = cast2Node(anIter->next());
7822 poly_nodes[iNode++] = n;
7823 if (n == nodes[il1]) {
7827 // add nodes to insert
7828 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7829 for (; nIt != aNodesToInsert.end(); nIt++) {
7830 poly_nodes[iNode++] = *nIt;
7832 // add nodes of face starting from last node of link
7833 while ( anIter->more() ) {
7834 poly_nodes[iNode++] = cast2Node(anIter->next());
7838 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7839 while ( nodeIt->more() && !isFLN ) {
7840 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7841 poly_nodes[iNode++] = n;
7842 if (n == nodes[il1]) {
7846 // add nodes to insert
7847 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7848 for (; nIt != aNodesToInsert.end(); nIt++) {
7849 poly_nodes[iNode++] = *nIt;
7851 // add nodes of face starting from last node of link
7852 while ( nodeIt->more() ) {
7853 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7854 poly_nodes[iNode++] = n;
7858 // edit or replace the face
7859 SMESHDS_Mesh *aMesh = GetMeshDS();
7861 if (theFace->IsPoly()) {
7862 aMesh->ChangePolygonNodes(theFace, poly_nodes);
7865 int aShapeId = FindShape( theFace );
7867 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7868 myLastCreatedElems.Append(newElem);
7869 if ( aShapeId && newElem )
7870 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7872 aMesh->RemoveElement(theFace);
7877 SMESHDS_Mesh *aMesh = GetMeshDS();
7878 if( !theFace->IsQuadratic() ) {
7880 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7881 int nbLinkNodes = 2 + aNodesToInsert.size();
7882 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7883 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7884 linkNodes[ 0 ] = nodes[ il1 ];
7885 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7886 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7887 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7888 linkNodes[ iNode++ ] = *nIt;
7890 // decide how to split a quadrangle: compare possible variants
7891 // and choose which of splits to be a quadrangle
7892 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7893 if ( nbFaceNodes == 3 ) {
7894 iBestQuad = nbSplits;
7897 else if ( nbFaceNodes == 4 ) {
7898 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7899 double aBestRate = DBL_MAX;
7900 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7902 double aBadRate = 0;
7903 // evaluate elements quality
7904 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7905 if ( iSplit == iQuad ) {
7906 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7910 aBadRate += getBadRate( &quad, aCrit );
7913 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7915 nodes[ iSplit < iQuad ? i4 : i3 ]);
7916 aBadRate += getBadRate( &tria, aCrit );
7920 if ( aBadRate < aBestRate ) {
7922 aBestRate = aBadRate;
7927 // create new elements
7928 int aShapeId = FindShape( theFace );
7931 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7932 SMDS_MeshElement* newElem = 0;
7933 if ( iSplit == iBestQuad )
7934 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7939 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7941 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7942 myLastCreatedElems.Append(newElem);
7943 if ( aShapeId && newElem )
7944 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7947 // change nodes of theFace
7948 const SMDS_MeshNode* newNodes[ 4 ];
7949 newNodes[ 0 ] = linkNodes[ i1 ];
7950 newNodes[ 1 ] = linkNodes[ i2 ];
7951 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7952 newNodes[ 3 ] = nodes[ i4 ];
7953 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7954 const SMDS_MeshElement* newElem = 0;
7955 if (iSplit == iBestQuad)
7956 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
7958 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
7959 myLastCreatedElems.Append(newElem);
7960 if ( aShapeId && newElem )
7961 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7962 } // end if(!theFace->IsQuadratic())
7963 else { // theFace is quadratic
7964 // we have to split theFace on simple triangles and one simple quadrangle
7966 int nbshift = tmp*2;
7967 // shift nodes in nodes[] by nbshift
7969 for(i=0; i<nbshift; i++) {
7970 const SMDS_MeshNode* n = nodes[0];
7971 for(j=0; j<nbFaceNodes-1; j++) {
7972 nodes[j] = nodes[j+1];
7974 nodes[nbFaceNodes-1] = n;
7976 il1 = il1 - nbshift;
7977 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7978 // n0 n1 n2 n0 n1 n2
7979 // +-----+-----+ +-----+-----+
7988 // create new elements
7989 int aShapeId = FindShape( theFace );
7992 if(nbFaceNodes==6) { // quadratic triangle
7993 SMDS_MeshElement* newElem =
7994 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7995 myLastCreatedElems.Append(newElem);
7996 if ( aShapeId && newElem )
7997 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7998 if(theFace->IsMediumNode(nodes[il1])) {
7999 // create quadrangle
8000 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8001 myLastCreatedElems.Append(newElem);
8002 if ( aShapeId && newElem )
8003 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8009 // create quadrangle
8010 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8011 myLastCreatedElems.Append(newElem);
8012 if ( aShapeId && newElem )
8013 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8019 else { // nbFaceNodes==8 - quadratic quadrangle
8020 SMDS_MeshElement* newElem =
8021 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8022 myLastCreatedElems.Append(newElem);
8023 if ( aShapeId && newElem )
8024 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8025 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8026 myLastCreatedElems.Append(newElem);
8027 if ( aShapeId && newElem )
8028 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8029 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8030 myLastCreatedElems.Append(newElem);
8031 if ( aShapeId && newElem )
8032 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8033 if(theFace->IsMediumNode(nodes[il1])) {
8034 // create quadrangle
8035 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8036 myLastCreatedElems.Append(newElem);
8037 if ( aShapeId && newElem )
8038 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8044 // create quadrangle
8045 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8046 myLastCreatedElems.Append(newElem);
8047 if ( aShapeId && newElem )
8048 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8054 // create needed triangles using n1,n2,n3 and inserted nodes
8055 int nbn = 2 + aNodesToInsert.size();
8056 //const SMDS_MeshNode* aNodes[nbn];
8057 vector<const SMDS_MeshNode*> aNodes(nbn);
8058 aNodes[0] = nodes[n1];
8059 aNodes[nbn-1] = nodes[n2];
8060 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8061 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8062 aNodes[iNode++] = *nIt;
8064 for(i=1; i<nbn; i++) {
8065 SMDS_MeshElement* newElem =
8066 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8067 myLastCreatedElems.Append(newElem);
8068 if ( aShapeId && newElem )
8069 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8073 aMesh->RemoveElement(theFace);
8076 //=======================================================================
8077 //function : UpdateVolumes
8079 //=======================================================================
8080 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8081 const SMDS_MeshNode* theBetweenNode2,
8082 list<const SMDS_MeshNode*>& theNodesToInsert)
8084 myLastCreatedElems.Clear();
8085 myLastCreatedNodes.Clear();
8087 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8088 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8089 const SMDS_MeshElement* elem = invElemIt->next();
8091 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8092 SMDS_VolumeTool aVolume (elem);
8093 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8096 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8097 int iface, nbFaces = aVolume.NbFaces();
8098 vector<const SMDS_MeshNode *> poly_nodes;
8099 vector<int> quantities (nbFaces);
8101 for (iface = 0; iface < nbFaces; iface++) {
8102 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8103 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8104 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8106 for (int inode = 0; inode < nbFaceNodes; inode++) {
8107 poly_nodes.push_back(faceNodes[inode]);
8109 if (nbInserted == 0) {
8110 if (faceNodes[inode] == theBetweenNode1) {
8111 if (faceNodes[inode + 1] == theBetweenNode2) {
8112 nbInserted = theNodesToInsert.size();
8114 // add nodes to insert
8115 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8116 for (; nIt != theNodesToInsert.end(); nIt++) {
8117 poly_nodes.push_back(*nIt);
8121 else if (faceNodes[inode] == theBetweenNode2) {
8122 if (faceNodes[inode + 1] == theBetweenNode1) {
8123 nbInserted = theNodesToInsert.size();
8125 // add nodes to insert in reversed order
8126 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8128 for (; nIt != theNodesToInsert.begin(); nIt--) {
8129 poly_nodes.push_back(*nIt);
8131 poly_nodes.push_back(*nIt);
8138 quantities[iface] = nbFaceNodes + nbInserted;
8141 // Replace or update the volume
8142 SMESHDS_Mesh *aMesh = GetMeshDS();
8144 if (elem->IsPoly()) {
8145 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8149 int aShapeId = FindShape( elem );
8151 SMDS_MeshElement* newElem =
8152 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8153 myLastCreatedElems.Append(newElem);
8154 if (aShapeId && newElem)
8155 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8157 aMesh->RemoveElement(elem);
8164 //================================================================================
8166 * \brief Transform any volume into data of SMDSEntity_Polyhedra
8168 //================================================================================
8170 void volumeToPolyhedron( const SMDS_MeshElement* elem,
8171 vector<const SMDS_MeshNode *> & nodes,
8172 vector<int> & nbNodeInFaces )
8175 nbNodeInFaces.clear();
8176 SMDS_VolumeTool vTool ( elem );
8177 for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
8179 const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
8180 nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
8181 nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
8186 //=======================================================================
8188 * \brief Convert elements contained in a submesh to quadratic
8189 * \return int - nb of checked elements
8191 //=======================================================================
8193 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8194 SMESH_MesherHelper& theHelper,
8195 const bool theForce3d)
8198 if( !theSm ) return nbElem;
8200 vector<int> nbNodeInFaces;
8201 vector<const SMDS_MeshNode *> nodes;
8202 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8203 while(ElemItr->more())
8206 const SMDS_MeshElement* elem = ElemItr->next();
8207 if( !elem ) continue;
8209 // analyse a necessity of conversion
8210 const SMDSAbs_ElementType aType = elem->GetType();
8211 if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
8213 const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
8214 bool hasCentralNodes = false;
8215 if ( elem->IsQuadratic() )
8218 switch ( aGeomType ) {
8219 case SMDSEntity_Quad_Triangle:
8220 case SMDSEntity_Quad_Quadrangle:
8221 case SMDSEntity_Quad_Hexa:
8222 alreadyOK = !theHelper.GetIsBiQuadratic(); break;
8224 case SMDSEntity_BiQuad_Triangle:
8225 case SMDSEntity_BiQuad_Quadrangle:
8226 case SMDSEntity_TriQuad_Hexa:
8227 alreadyOK = theHelper.GetIsBiQuadratic();
8228 hasCentralNodes = true;
8233 // take into account already present modium nodes
8235 case SMDSAbs_Volume:
8236 theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
8238 theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
8240 theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
8246 // get elem data needed to re-create it
8248 const int id = elem->GetID();
8249 const int nbNodes = elem->NbCornerNodes();
8250 nodes.assign(elem->begin_nodes(), elem->end_nodes());
8251 if ( aGeomType == SMDSEntity_Polyhedra )
8252 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
8253 else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
8254 volumeToPolyhedron( elem, nodes, nbNodeInFaces );
8256 // remove a linear element
8257 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8259 // remove central nodes of biquadratic elements (biquad->quad convertion)
8260 if ( hasCentralNodes )
8261 for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
8262 if ( nodes[i]->NbInverseElements() == 0 )
8263 GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
8265 const SMDS_MeshElement* NewElem = 0;
8271 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8279 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8282 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8285 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8289 case SMDSAbs_Volume :
8293 case SMDSEntity_Tetra:
8294 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8296 case SMDSEntity_Pyramid:
8297 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8299 case SMDSEntity_Penta:
8300 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8302 case SMDSEntity_Hexa:
8303 case SMDSEntity_Quad_Hexa:
8304 case SMDSEntity_TriQuad_Hexa:
8305 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8306 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8308 case SMDSEntity_Hexagonal_Prism:
8310 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8317 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8318 if( NewElem && NewElem->getshapeId() < 1 )
8319 theSm->AddElement( NewElem );
8323 //=======================================================================
8324 //function : ConvertToQuadratic
8326 //=======================================================================
8328 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
8330 SMESHDS_Mesh* meshDS = GetMeshDS();
8332 SMESH_MesherHelper aHelper(*myMesh);
8334 aHelper.SetIsQuadratic( true );
8335 aHelper.SetIsBiQuadratic( theToBiQuad );
8336 aHelper.SetElementsOnShape(true);
8338 // convert elements assigned to sub-meshes
8339 int nbCheckedElems = 0;
8340 if ( myMesh->HasShapeToMesh() )
8342 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8344 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8345 while ( smIt->more() ) {
8346 SMESH_subMesh* sm = smIt->next();
8347 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8348 aHelper.SetSubShape( sm->GetSubShape() );
8349 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8355 // convert elements NOT assigned to sub-meshes
8356 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8357 if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
8359 aHelper.SetElementsOnShape(false);
8360 SMESHDS_SubMesh *smDS = 0;
8363 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8364 while( aEdgeItr->more() )
8366 const SMDS_MeshEdge* edge = aEdgeItr->next();
8367 if ( !edge->IsQuadratic() )
8369 int id = edge->GetID();
8370 const SMDS_MeshNode* n1 = edge->GetNode(0);
8371 const SMDS_MeshNode* n2 = edge->GetNode(1);
8373 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8375 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8376 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8380 aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
8385 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8386 while( aFaceItr->more() )
8388 const SMDS_MeshFace* face = aFaceItr->next();
8389 if ( !face ) continue;
8391 const SMDSAbs_EntityType type = face->GetEntityType();
8395 case SMDSEntity_Quad_Triangle:
8396 case SMDSEntity_Quad_Quadrangle:
8397 alreadyOK = !theToBiQuad;
8398 aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8400 case SMDSEntity_BiQuad_Triangle:
8401 case SMDSEntity_BiQuad_Quadrangle:
8402 alreadyOK = theToBiQuad;
8403 aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8405 default: alreadyOK = false;
8410 const int id = face->GetID();
8411 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8413 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8415 SMDS_MeshFace * NewFace = 0;
8418 case SMDSEntity_Triangle:
8419 case SMDSEntity_Quad_Triangle:
8420 case SMDSEntity_BiQuad_Triangle:
8421 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8422 if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
8423 GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
8426 case SMDSEntity_Quadrangle:
8427 case SMDSEntity_Quad_Quadrangle:
8428 case SMDSEntity_BiQuad_Quadrangle:
8429 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8430 if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
8431 GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
8435 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8437 ReplaceElemInGroups( face, NewFace, GetMeshDS());
8441 vector<int> nbNodeInFaces;
8442 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8443 while(aVolumeItr->more())
8445 const SMDS_MeshVolume* volume = aVolumeItr->next();
8446 if ( !volume ) continue;
8448 const SMDSAbs_EntityType type = volume->GetEntityType();
8449 if ( volume->IsQuadratic() )
8454 case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break;
8455 case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
8456 default: alreadyOK = true;
8460 aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
8464 const int id = volume->GetID();
8465 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8466 if ( type == SMDSEntity_Polyhedra )
8467 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
8468 else if ( type == SMDSEntity_Hexagonal_Prism )
8469 volumeToPolyhedron( volume, nodes, nbNodeInFaces );
8471 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8473 SMDS_MeshVolume * NewVolume = 0;
8476 case SMDSEntity_Tetra:
8477 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
8479 case SMDSEntity_Hexa:
8480 case SMDSEntity_Quad_Hexa:
8481 case SMDSEntity_TriQuad_Hexa:
8482 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8483 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8484 for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
8485 if ( nodes[i]->NbInverseElements() == 0 )
8486 GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
8488 case SMDSEntity_Pyramid:
8489 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8490 nodes[3], nodes[4], id, theForce3d);
8492 case SMDSEntity_Penta:
8493 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8494 nodes[3], nodes[4], nodes[5], id, theForce3d);
8496 case SMDSEntity_Hexagonal_Prism:
8498 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8500 ReplaceElemInGroups(volume, NewVolume, meshDS);
8505 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8506 // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8507 // aHelper.FixQuadraticElements(myError);
8508 SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8512 //================================================================================
8514 * \brief Makes given elements quadratic
8515 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
8516 * \param theElements - elements to make quadratic
8518 //================================================================================
8520 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
8521 TIDSortedElemSet& theElements,
8522 const bool theToBiQuad)
8524 if ( theElements.empty() ) return;
8526 // we believe that all theElements are of the same type
8527 const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
8529 // get all nodes shared by theElements
8530 TIDSortedNodeSet allNodes;
8531 TIDSortedElemSet::iterator eIt = theElements.begin();
8532 for ( ; eIt != theElements.end(); ++eIt )
8533 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
8535 // complete theElements with elements of lower dim whose all nodes are in allNodes
8537 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
8538 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
8539 TIDSortedNodeSet::iterator nIt = allNodes.begin();
8540 for ( ; nIt != allNodes.end(); ++nIt )
8542 const SMDS_MeshNode* n = *nIt;
8543 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
8544 while ( invIt->more() )
8546 const SMDS_MeshElement* e = invIt->next();
8547 const SMDSAbs_ElementType type = e->GetType();
8548 if ( e->IsQuadratic() )
8550 quadAdjacentElems[ type ].insert( e );
8553 switch ( e->GetEntityType() ) {
8554 case SMDSEntity_Quad_Triangle:
8555 case SMDSEntity_Quad_Quadrangle:
8556 case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break;
8557 case SMDSEntity_BiQuad_Triangle:
8558 case SMDSEntity_BiQuad_Quadrangle:
8559 case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
8560 default: alreadyOK = true;
8565 if ( type >= elemType )
8566 continue; // same type or more complex linear element
8568 if ( !checkedAdjacentElems[ type ].insert( e ).second )
8569 continue; // e is already checked
8573 SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
8574 while ( nodeIt->more() && allIn )
8575 allIn = allNodes.count( nodeIt->next() );
8577 theElements.insert(e );
8581 SMESH_MesherHelper helper(*myMesh);
8582 helper.SetIsQuadratic( true );
8583 helper.SetIsBiQuadratic( theToBiQuad );
8585 // add links of quadratic adjacent elements to the helper
8587 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
8588 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
8589 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
8591 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
8593 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
8594 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
8595 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
8597 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
8599 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
8600 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
8601 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
8603 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
8606 // make quadratic (or bi-tri-quadratic) elements instead of linear ones
8608 SMESHDS_Mesh* meshDS = GetMeshDS();
8609 SMESHDS_SubMesh* smDS = 0;
8610 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
8612 const SMDS_MeshElement* elem = *eIt;
8615 int nbCentralNodes = 0;
8616 switch ( elem->GetEntityType() ) {
8617 // linear convertible
8618 case SMDSEntity_Edge:
8619 case SMDSEntity_Triangle:
8620 case SMDSEntity_Quadrangle:
8621 case SMDSEntity_Tetra:
8622 case SMDSEntity_Pyramid:
8623 case SMDSEntity_Hexa:
8624 case SMDSEntity_Penta: alreadyOK = false; nbCentralNodes = 0; break;
8625 // quadratic that can become bi-quadratic
8626 case SMDSEntity_Quad_Triangle:
8627 case SMDSEntity_Quad_Quadrangle:
8628 case SMDSEntity_Quad_Hexa: alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
8630 case SMDSEntity_BiQuad_Triangle:
8631 case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
8632 case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
8634 default: alreadyOK = true;
8636 if ( alreadyOK ) continue;
8638 const SMDSAbs_ElementType type = elem->GetType();
8639 const int id = elem->GetID();
8640 const int nbNodes = elem->NbCornerNodes();
8641 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
8643 helper.SetSubShape( elem->getshapeId() );
8645 if ( !smDS || !smDS->Contains( elem ))
8646 smDS = meshDS->MeshElements( elem->getshapeId() );
8647 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
8649 SMDS_MeshElement * newElem = 0;
8652 case 4: // cases for most frequently used element types go first (for optimization)
8653 if ( type == SMDSAbs_Volume )
8654 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8656 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8659 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8660 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8663 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
8666 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8669 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8670 nodes[4], id, theForce3d);
8673 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8674 nodes[4], nodes[5], id, theForce3d);
8678 ReplaceElemInGroups( elem, newElem, meshDS);
8679 if( newElem && smDS )
8680 smDS->AddElement( newElem );
8682 // remove central nodes
8683 for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
8684 if ( nodes[i]->NbInverseElements() == 0 )
8685 meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
8687 } // loop on theElements
8690 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8691 // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8692 // helper.FixQuadraticElements( myError );
8693 SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
8697 //=======================================================================
8699 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8700 * \return int - nb of checked elements
8702 //=======================================================================
8704 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
8705 SMDS_ElemIteratorPtr theItr,
8706 const int theShapeID)
8709 SMESHDS_Mesh* meshDS = GetMeshDS();
8711 while( theItr->more() )
8713 const SMDS_MeshElement* elem = theItr->next();
8715 if( elem && elem->IsQuadratic())
8717 int id = elem->GetID();
8718 int nbCornerNodes = elem->NbCornerNodes();
8719 SMDSAbs_ElementType aType = elem->GetType();
8721 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
8723 //remove a quadratic element
8724 if ( !theSm || !theSm->Contains( elem ))
8725 theSm = meshDS->MeshElements( elem->getshapeId() );
8726 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
8728 // remove medium nodes
8729 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
8730 if ( nodes[i]->NbInverseElements() == 0 )
8731 meshDS->RemoveFreeNode( nodes[i], theSm );
8733 // add a linear element
8734 nodes.resize( nbCornerNodes );
8735 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
8736 ReplaceElemInGroups(elem, newElem, meshDS);
8737 if( theSm && newElem )
8738 theSm->AddElement( newElem );
8744 //=======================================================================
8745 //function : ConvertFromQuadratic
8747 //=======================================================================
8749 bool SMESH_MeshEditor::ConvertFromQuadratic()
8751 int nbCheckedElems = 0;
8752 if ( myMesh->HasShapeToMesh() )
8754 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8756 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8757 while ( smIt->more() ) {
8758 SMESH_subMesh* sm = smIt->next();
8759 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8760 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8766 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8767 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8769 SMESHDS_SubMesh *aSM = 0;
8770 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8778 //================================================================================
8780 * \brief Return true if all medium nodes of the element are in the node set
8782 //================================================================================
8784 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
8786 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
8787 if ( !nodeSet.count( elem->GetNode(i) ))
8793 //================================================================================
8795 * \brief Makes given elements linear
8797 //================================================================================
8799 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
8801 if ( theElements.empty() ) return;
8803 // collect IDs of medium nodes of theElements; some of these nodes will be removed
8804 set<int> mediumNodeIDs;
8805 TIDSortedElemSet::iterator eIt = theElements.begin();
8806 for ( ; eIt != theElements.end(); ++eIt )
8808 const SMDS_MeshElement* e = *eIt;
8809 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
8810 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
8813 // replace given elements by linear ones
8814 SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
8815 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8817 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
8818 // except those elements sharing medium nodes of quadratic element whose medium nodes
8819 // are not all in mediumNodeIDs
8821 // get remaining medium nodes
8822 TIDSortedNodeSet mediumNodes;
8823 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
8824 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
8825 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
8826 mediumNodes.insert( mediumNodes.end(), n );
8828 // find more quadratic elements to convert
8829 TIDSortedElemSet moreElemsToConvert;
8830 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
8831 for ( ; nIt != mediumNodes.end(); ++nIt )
8833 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
8834 while ( invIt->more() )
8836 const SMDS_MeshElement* e = invIt->next();
8837 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
8839 // find a more complex element including e and
8840 // whose medium nodes are not in mediumNodes
8841 bool complexFound = false;
8842 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
8844 SMDS_ElemIteratorPtr invIt2 =
8845 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
8846 while ( invIt2->more() )
8848 const SMDS_MeshElement* eComplex = invIt2->next();
8849 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
8851 int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
8852 if ( nbCommonNodes == e->NbNodes())
8854 complexFound = true;
8855 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
8861 if ( !complexFound )
8862 moreElemsToConvert.insert( e );
8866 elemIt = elemSetIterator( moreElemsToConvert );
8867 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
8870 //=======================================================================
8871 //function : SewSideElements
8873 //=======================================================================
8875 SMESH_MeshEditor::Sew_Error
8876 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
8877 TIDSortedElemSet& theSide2,
8878 const SMDS_MeshNode* theFirstNode1,
8879 const SMDS_MeshNode* theFirstNode2,
8880 const SMDS_MeshNode* theSecondNode1,
8881 const SMDS_MeshNode* theSecondNode2)
8883 myLastCreatedElems.Clear();
8884 myLastCreatedNodes.Clear();
8886 MESSAGE ("::::SewSideElements()");
8887 if ( theSide1.size() != theSide2.size() )
8888 return SEW_DIFF_NB_OF_ELEMENTS;
8890 Sew_Error aResult = SEW_OK;
8892 // 1. Build set of faces representing each side
8893 // 2. Find which nodes of the side 1 to merge with ones on the side 2
8894 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8896 // =======================================================================
8897 // 1. Build set of faces representing each side:
8898 // =======================================================================
8899 // a. build set of nodes belonging to faces
8900 // b. complete set of faces: find missing faces whose nodes are in set of nodes
8901 // c. create temporary faces representing side of volumes if correspondent
8902 // face does not exist
8904 SMESHDS_Mesh* aMesh = GetMeshDS();
8905 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
8906 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
8907 TIDSortedElemSet faceSet1, faceSet2;
8908 set<const SMDS_MeshElement*> volSet1, volSet2;
8909 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
8910 TIDSortedElemSet * faceSetPtr[] = { &faceSet1, &faceSet2 };
8911 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
8912 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8913 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8914 int iSide, iFace, iNode;
8916 list<const SMDS_MeshElement* > tempFaceList;
8917 for ( iSide = 0; iSide < 2; iSide++ ) {
8918 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
8919 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8920 TIDSortedElemSet * faceSet = faceSetPtr[ iSide ];
8921 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
8922 set<const SMDS_MeshElement*>::iterator vIt;
8923 TIDSortedElemSet::iterator eIt;
8924 set<const SMDS_MeshNode*>::iterator nIt;
8926 // check that given nodes belong to given elements
8927 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8928 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8929 int firstIndex = -1, secondIndex = -1;
8930 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8931 const SMDS_MeshElement* elem = *eIt;
8932 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
8933 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8934 if ( firstIndex > -1 && secondIndex > -1 ) break;
8936 if ( firstIndex < 0 || secondIndex < 0 ) {
8937 // we can simply return until temporary faces created
8938 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8941 // -----------------------------------------------------------
8942 // 1a. Collect nodes of existing faces
8943 // and build set of face nodes in order to detect missing
8944 // faces corresponding to sides of volumes
8945 // -----------------------------------------------------------
8947 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8949 // loop on the given element of a side
8950 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8951 //const SMDS_MeshElement* elem = *eIt;
8952 const SMDS_MeshElement* elem = *eIt;
8953 if ( elem->GetType() == SMDSAbs_Face ) {
8954 faceSet->insert( elem );
8955 set <const SMDS_MeshNode*> faceNodeSet;
8956 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8957 while ( nodeIt->more() ) {
8958 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8959 nodeSet->insert( n );
8960 faceNodeSet.insert( n );
8962 setOfFaceNodeSet.insert( faceNodeSet );
8964 else if ( elem->GetType() == SMDSAbs_Volume )
8965 volSet->insert( elem );
8967 // ------------------------------------------------------------------------------
8968 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
8969 // ------------------------------------------------------------------------------
8971 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8972 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8973 while ( fIt->more() ) { // loop on faces sharing a node
8974 const SMDS_MeshElement* f = fIt->next();
8975 if ( faceSet->find( f ) == faceSet->end() ) {
8976 // check if all nodes are in nodeSet and
8977 // complete setOfFaceNodeSet if they are
8978 set <const SMDS_MeshNode*> faceNodeSet;
8979 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8980 bool allInSet = true;
8981 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8982 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8983 if ( nodeSet->find( n ) == nodeSet->end() )
8986 faceNodeSet.insert( n );
8989 faceSet->insert( f );
8990 setOfFaceNodeSet.insert( faceNodeSet );
8996 // -------------------------------------------------------------------------
8997 // 1c. Create temporary faces representing sides of volumes if correspondent
8998 // face does not exist
8999 // -------------------------------------------------------------------------
9001 if ( !volSet->empty() ) {
9002 //int nodeSetSize = nodeSet->size();
9004 // loop on given volumes
9005 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9006 SMDS_VolumeTool vol (*vIt);
9007 // loop on volume faces: find free faces
9008 // --------------------------------------
9009 list<const SMDS_MeshElement* > freeFaceList;
9010 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9011 if ( !vol.IsFreeFace( iFace ))
9013 // check if there is already a face with same nodes in a face set
9014 const SMDS_MeshElement* aFreeFace = 0;
9015 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9016 int nbNodes = vol.NbFaceNodes( iFace );
9017 set <const SMDS_MeshNode*> faceNodeSet;
9018 vol.GetFaceNodes( iFace, faceNodeSet );
9019 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9021 // no such a face is given but it still can exist, check it
9022 vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
9023 aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
9026 // create a temporary face
9027 if ( nbNodes == 3 ) {
9028 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9029 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9031 else if ( nbNodes == 4 ) {
9032 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9033 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9036 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9037 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9038 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9041 tempFaceList.push_back( aFreeFace );
9045 freeFaceList.push_back( aFreeFace );
9047 } // loop on faces of a volume
9049 // choose one of several free faces of a volume
9050 // --------------------------------------------
9051 if ( freeFaceList.size() > 1 ) {
9052 // choose a face having max nb of nodes shared by other elems of a side
9053 int maxNbNodes = -1;
9054 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9055 while ( fIt != freeFaceList.end() ) { // loop on free faces
9056 int nbSharedNodes = 0;
9057 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9058 while ( nodeIt->more() ) { // loop on free face nodes
9059 const SMDS_MeshNode* n =
9060 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9061 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9062 while ( invElemIt->more() ) {
9063 const SMDS_MeshElement* e = invElemIt->next();
9064 nbSharedNodes += faceSet->count( e );
9065 nbSharedNodes += elemSet->count( e );
9068 if ( nbSharedNodes > maxNbNodes ) {
9069 maxNbNodes = nbSharedNodes;
9070 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9072 else if ( nbSharedNodes == maxNbNodes ) {
9076 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9079 if ( freeFaceList.size() > 1 )
9081 // could not choose one face, use another way
9082 // choose a face most close to the bary center of the opposite side
9083 gp_XYZ aBC( 0., 0., 0. );
9084 set <const SMDS_MeshNode*> addedNodes;
9085 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9086 eIt = elemSet2->begin();
9087 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9088 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9089 while ( nodeIt->more() ) { // loop on free face nodes
9090 const SMDS_MeshNode* n =
9091 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9092 if ( addedNodes.insert( n ).second )
9093 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9096 aBC /= addedNodes.size();
9097 double minDist = DBL_MAX;
9098 fIt = freeFaceList.begin();
9099 while ( fIt != freeFaceList.end() ) { // loop on free faces
9101 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9102 while ( nodeIt->more() ) { // loop on free face nodes
9103 const SMDS_MeshNode* n =
9104 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9105 gp_XYZ p( n->X(),n->Y(),n->Z() );
9106 dist += ( aBC - p ).SquareModulus();
9108 if ( dist < minDist ) {
9110 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9113 fIt = freeFaceList.erase( fIt++ );
9116 } // choose one of several free faces of a volume
9118 if ( freeFaceList.size() == 1 ) {
9119 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9120 faceSet->insert( aFreeFace );
9121 // complete a node set with nodes of a found free face
9122 // for ( iNode = 0; iNode < ; iNode++ )
9123 // nodeSet->insert( fNodes[ iNode ] );
9126 } // loop on volumes of a side
9128 // // complete a set of faces if new nodes in a nodeSet appeared
9129 // // ----------------------------------------------------------
9130 // if ( nodeSetSize != nodeSet->size() ) {
9131 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9132 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9133 // while ( fIt->more() ) { // loop on faces sharing a node
9134 // const SMDS_MeshElement* f = fIt->next();
9135 // if ( faceSet->find( f ) == faceSet->end() ) {
9136 // // check if all nodes are in nodeSet and
9137 // // complete setOfFaceNodeSet if they are
9138 // set <const SMDS_MeshNode*> faceNodeSet;
9139 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9140 // bool allInSet = true;
9141 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9142 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9143 // if ( nodeSet->find( n ) == nodeSet->end() )
9144 // allInSet = false;
9146 // faceNodeSet.insert( n );
9148 // if ( allInSet ) {
9149 // faceSet->insert( f );
9150 // setOfFaceNodeSet.insert( faceNodeSet );
9156 } // Create temporary faces, if there are volumes given
9159 if ( faceSet1.size() != faceSet2.size() ) {
9160 // delete temporary faces: they are in reverseElements of actual nodes
9161 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9162 // while ( tmpFaceIt->more() )
9163 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9164 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9165 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9166 // aMesh->RemoveElement(*tmpFaceIt);
9167 MESSAGE("Diff nb of faces");
9168 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9171 // ============================================================
9172 // 2. Find nodes to merge:
9173 // bind a node to remove to a node to put instead
9174 // ============================================================
9176 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9177 if ( theFirstNode1 != theFirstNode2 )
9178 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9179 if ( theSecondNode1 != theSecondNode2 )
9180 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9182 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9183 set< long > linkIdSet; // links to process
9184 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9186 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9187 list< NLink > linkList[2];
9188 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9189 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9190 // loop on links in linkList; find faces by links and append links
9191 // of the found faces to linkList
9192 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9193 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9195 NLink link[] = { *linkIt[0], *linkIt[1] };
9196 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9197 if ( !linkIdSet.count( linkID ) )
9200 // by links, find faces in the face sets,
9201 // and find indices of link nodes in the found faces;
9202 // in a face set, there is only one or no face sharing a link
9203 // ---------------------------------------------------------------
9205 const SMDS_MeshElement* face[] = { 0, 0 };
9206 vector<const SMDS_MeshNode*> fnodes[2];
9207 int iLinkNode[2][2];
9208 TIDSortedElemSet avoidSet;
9209 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9210 const SMDS_MeshNode* n1 = link[iSide].first;
9211 const SMDS_MeshNode* n2 = link[iSide].second;
9212 //cout << "Side " << iSide << " ";
9213 //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9214 // find a face by two link nodes
9215 face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
9216 *faceSetPtr[ iSide ], avoidSet,
9217 &iLinkNode[iSide][0],
9218 &iLinkNode[iSide][1] );
9221 //cout << " F " << face[ iSide]->GetID() <<endl;
9222 faceSetPtr[ iSide ]->erase( face[ iSide ]);
9223 // put face nodes to fnodes
9224 if ( face[ iSide ]->IsQuadratic() )
9226 // use interlaced nodes iterator
9227 const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
9228 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9229 SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
9230 while ( nIter->more() )
9231 fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
9235 fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
9236 face[ iSide ]->end_nodes() );
9238 fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9242 // check similarity of elements of the sides
9243 if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9244 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9245 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9246 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9249 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9251 break; // do not return because it's necessary to remove tmp faces
9254 // set nodes to merge
9255 // -------------------
9257 if ( face[0] && face[1] ) {
9258 const int nbNodes = face[0]->NbNodes();
9259 if ( nbNodes != face[1]->NbNodes() ) {
9260 MESSAGE("Diff nb of face nodes");
9261 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9262 break; // do not return because it s necessary to remove tmp faces
9264 bool reverse[] = { false, false }; // order of nodes in the link
9265 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9266 // analyse link orientation in faces
9267 int i1 = iLinkNode[ iSide ][ 0 ];
9268 int i2 = iLinkNode[ iSide ][ 1 ];
9269 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9271 int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9272 int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9273 for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9275 nReplaceMap.insert ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9276 fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9279 // add other links of the faces to linkList
9280 // -----------------------------------------
9282 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9283 linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9284 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9285 if ( !iter_isnew.second ) { // already in a set: no need to process
9286 linkIdSet.erase( iter_isnew.first );
9288 else // new in set == encountered for the first time: add
9290 const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9291 const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9292 linkList[0].push_back ( NLink( n1, n2 ));
9293 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9298 if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9301 } // loop on link lists
9303 if ( aResult == SEW_OK &&
9304 ( //linkIt[0] != linkList[0].end() ||
9305 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9306 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9307 " " << (faceSetPtr[1]->empty()));
9308 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9311 // ====================================================================
9312 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9313 // ====================================================================
9315 // delete temporary faces
9316 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9317 // while ( tmpFaceIt->more() )
9318 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9319 list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9320 for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9321 aMesh->RemoveElement(*tmpFaceIt);
9323 if ( aResult != SEW_OK)
9326 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9327 // loop on nodes replacement map
9328 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9329 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9330 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9331 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9332 nodeIDsToRemove.push_back( nToRemove->GetID() );
9333 // loop on elements sharing nToRemove
9334 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9335 while ( invElemIt->more() ) {
9336 const SMDS_MeshElement* e = invElemIt->next();
9337 // get a new suite of nodes: make replacement
9338 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9339 vector< const SMDS_MeshNode*> nodes( nbNodes );
9340 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9341 while ( nIt->more() ) {
9342 const SMDS_MeshNode* n =
9343 static_cast<const SMDS_MeshNode*>( nIt->next() );
9344 nnIt = nReplaceMap.find( n );
9345 if ( nnIt != nReplaceMap.end() ) {
9351 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9352 // elemIDsToRemove.push_back( e->GetID() );
9356 SMDSAbs_ElementType etyp = e->GetType();
9357 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
9360 myLastCreatedElems.Append(newElem);
9361 AddToSameGroups(newElem, e, aMesh);
9362 int aShapeId = e->getshapeId();
9365 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9368 aMesh->RemoveElement(e);
9373 Remove( nodeIDsToRemove, true );
9378 //================================================================================
9380 * \brief Find corresponding nodes in two sets of faces
9381 * \param theSide1 - first face set
9382 * \param theSide2 - second first face
9383 * \param theFirstNode1 - a boundary node of set 1
9384 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9385 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9386 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9387 * \param nReplaceMap - output map of corresponding nodes
9388 * \return bool - is a success or not
9390 //================================================================================
9393 //#define DEBUG_MATCHING_NODES
9396 SMESH_MeshEditor::Sew_Error
9397 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9398 set<const SMDS_MeshElement*>& theSide2,
9399 const SMDS_MeshNode* theFirstNode1,
9400 const SMDS_MeshNode* theFirstNode2,
9401 const SMDS_MeshNode* theSecondNode1,
9402 const SMDS_MeshNode* theSecondNode2,
9403 TNodeNodeMap & nReplaceMap)
9405 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9407 nReplaceMap.clear();
9408 if ( theFirstNode1 != theFirstNode2 )
9409 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9410 if ( theSecondNode1 != theSecondNode2 )
9411 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9413 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9414 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9416 list< NLink > linkList[2];
9417 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9418 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9420 // loop on links in linkList; find faces by links and append links
9421 // of the found faces to linkList
9422 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9423 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9424 NLink link[] = { *linkIt[0], *linkIt[1] };
9425 if ( linkSet.find( link[0] ) == linkSet.end() )
9428 // by links, find faces in the face sets,
9429 // and find indices of link nodes in the found faces;
9430 // in a face set, there is only one or no face sharing a link
9431 // ---------------------------------------------------------------
9433 const SMDS_MeshElement* face[] = { 0, 0 };
9434 list<const SMDS_MeshNode*> notLinkNodes[2];
9435 //bool reverse[] = { false, false }; // order of notLinkNodes
9437 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9439 const SMDS_MeshNode* n1 = link[iSide].first;
9440 const SMDS_MeshNode* n2 = link[iSide].second;
9441 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9442 set< const SMDS_MeshElement* > facesOfNode1;
9443 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9445 // during a loop of the first node, we find all faces around n1,
9446 // during a loop of the second node, we find one face sharing both n1 and n2
9447 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9448 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9449 while ( fIt->more() ) { // loop on faces sharing a node
9450 const SMDS_MeshElement* f = fIt->next();
9451 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9452 ! facesOfNode1.insert( f ).second ) // f encounters twice
9454 if ( face[ iSide ] ) {
9455 MESSAGE( "2 faces per link " );
9456 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9459 faceSet->erase( f );
9461 // get not link nodes
9462 int nbN = f->NbNodes();
9463 if ( f->IsQuadratic() )
9465 nbNodes[ iSide ] = nbN;
9466 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9467 int i1 = f->GetNodeIndex( n1 );
9468 int i2 = f->GetNodeIndex( n2 );
9469 int iEnd = nbN, iBeg = -1, iDelta = 1;
9470 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9472 std::swap( iEnd, iBeg ); iDelta = -1;
9477 if ( i == iEnd ) i = iBeg + iDelta;
9478 if ( i == i1 ) break;
9479 nodes.push_back ( f->GetNode( i ) );
9485 // check similarity of elements of the sides
9486 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9487 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9488 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9489 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9492 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9496 // set nodes to merge
9497 // -------------------
9499 if ( face[0] && face[1] ) {
9500 if ( nbNodes[0] != nbNodes[1] ) {
9501 MESSAGE("Diff nb of face nodes");
9502 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9504 #ifdef DEBUG_MATCHING_NODES
9505 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9506 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9507 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9509 int nbN = nbNodes[0];
9511 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9512 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9513 for ( int i = 0 ; i < nbN - 2; ++i ) {
9514 #ifdef DEBUG_MATCHING_NODES
9515 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9517 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9521 // add other links of the face 1 to linkList
9522 // -----------------------------------------
9524 const SMDS_MeshElement* f0 = face[0];
9525 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9526 for ( int i = 0; i < nbN; i++ )
9528 const SMDS_MeshNode* n2 = f0->GetNode( i );
9529 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9530 linkSet.insert( SMESH_TLink( n1, n2 ));
9531 if ( !iter_isnew.second ) { // already in a set: no need to process
9532 linkSet.erase( iter_isnew.first );
9534 else // new in set == encountered for the first time: add
9536 #ifdef DEBUG_MATCHING_NODES
9537 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9538 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9540 linkList[0].push_back ( NLink( n1, n2 ));
9541 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9546 } // loop on link lists
9551 //================================================================================
9553 * \brief Create elements equal (on same nodes) to given ones
9554 * \param [in] theElements - a set of elems to duplicate. If it is empty, all
9555 * elements of the uppest dimension are duplicated.
9557 //================================================================================
9559 void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
9562 SMESHDS_Mesh* mesh = GetMeshDS();
9564 // get an element type and an iterator over elements
9566 SMDSAbs_ElementType type;
9567 SMDS_ElemIteratorPtr elemIt;
9568 vector< const SMDS_MeshElement* > allElems;
9569 if ( theElements.empty() )
9571 if ( mesh->NbNodes() == 0 )
9573 // get most complex type
9574 SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
9575 SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
9576 SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
9578 for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
9579 if ( mesh->GetMeshInfo().NbElements( types[i] ))
9584 // put all elements in the vector <allElems>
9585 allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
9586 elemIt = mesh->elementsIterator( type );
9587 while ( elemIt->more() )
9588 allElems.push_back( elemIt->next());
9589 elemIt = elemSetIterator( allElems );
9593 type = (*theElements.begin())->GetType();
9594 elemIt = elemSetIterator( theElements );
9597 // duplicate elements
9599 if ( type == SMDSAbs_Ball )
9601 SMDS_UnstructuredGrid* vtkGrid = mesh->getGrid();
9602 while ( elemIt->more() )
9604 const SMDS_MeshElement* elem = elemIt->next();
9605 if ( elem->GetType() != SMDSAbs_Ball )
9607 if (( elem = mesh->AddBall( elem->GetNode(0),
9608 vtkGrid->GetBallDiameter( elem->getVtkId() ))))
9609 myLastCreatedElems.Append( elem );
9614 vector< const SMDS_MeshNode* > nodes;
9615 while ( elemIt->more() )
9617 const SMDS_MeshElement* elem = elemIt->next();
9618 if ( elem->GetType() != type )
9621 nodes.assign( elem->begin_nodes(), elem->end_nodes() );
9623 if ( type == SMDSAbs_Volume && elem->GetVtkType() == VTK_POLYHEDRON )
9625 std::vector<int> quantities =
9626 static_cast< const SMDS_VtkVolume* >( elem )->GetQuantities();
9627 elem = mesh->AddPolyhedralVolume( nodes, quantities );
9631 AddElement( nodes, type, elem->IsPoly() );
9632 elem = 0; // myLastCreatedElems is already filled
9635 myLastCreatedElems.Append( elem );
9640 //================================================================================
9642 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9643 \param theElems - the list of elements (edges or faces) to be replicated
9644 The nodes for duplication could be found from these elements
9645 \param theNodesNot - list of nodes to NOT replicate
9646 \param theAffectedElems - the list of elements (cells and edges) to which the
9647 replicated nodes should be associated to.
9648 \return TRUE if operation has been completed successfully, FALSE otherwise
9650 //================================================================================
9652 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9653 const TIDSortedElemSet& theNodesNot,
9654 const TIDSortedElemSet& theAffectedElems )
9656 myLastCreatedElems.Clear();
9657 myLastCreatedNodes.Clear();
9659 if ( theElems.size() == 0 )
9662 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9667 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9668 // duplicate elements and nodes
9669 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9670 // replce nodes by duplications
9671 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9675 //================================================================================
9677 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9678 \param theMeshDS - mesh instance
9679 \param theElems - the elements replicated or modified (nodes should be changed)
9680 \param theNodesNot - nodes to NOT replicate
9681 \param theNodeNodeMap - relation of old node to new created node
9682 \param theIsDoubleElem - flag os to replicate element or modify
9683 \return TRUE if operation has been completed successfully, FALSE otherwise
9685 //================================================================================
9687 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9688 const TIDSortedElemSet& theElems,
9689 const TIDSortedElemSet& theNodesNot,
9690 std::map< const SMDS_MeshNode*,
9691 const SMDS_MeshNode* >& theNodeNodeMap,
9692 const bool theIsDoubleElem )
9694 MESSAGE("doubleNodes");
9695 // iterate on through element and duplicate them (by nodes duplication)
9697 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9698 for ( ; elemItr != theElems.end(); ++elemItr )
9700 const SMDS_MeshElement* anElem = *elemItr;
9704 bool isDuplicate = false;
9705 // duplicate nodes to duplicate element
9706 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9707 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9709 while ( anIter->more() )
9712 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9713 SMDS_MeshNode* aNewNode = aCurrNode;
9714 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9715 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9716 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9719 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9720 theNodeNodeMap[ aCurrNode ] = aNewNode;
9721 myLastCreatedNodes.Append( aNewNode );
9723 isDuplicate |= (aCurrNode != aNewNode);
9724 newNodes[ ind++ ] = aNewNode;
9729 if ( theIsDoubleElem )
9730 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9733 MESSAGE("ChangeElementNodes");
9734 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9741 //================================================================================
9743 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9744 \param theNodes - identifiers of nodes to be doubled
9745 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9746 nodes. If list of element identifiers is empty then nodes are doubled but
9747 they not assigned to elements
9748 \return TRUE if operation has been completed successfully, FALSE otherwise
9750 //================================================================================
9752 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9753 const std::list< int >& theListOfModifiedElems )
9755 MESSAGE("DoubleNodes");
9756 myLastCreatedElems.Clear();
9757 myLastCreatedNodes.Clear();
9759 if ( theListOfNodes.size() == 0 )
9762 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9766 // iterate through nodes and duplicate them
9768 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9770 std::list< int >::const_iterator aNodeIter;
9771 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9773 int aCurr = *aNodeIter;
9774 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9780 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9783 anOldNodeToNewNode[ aNode ] = aNewNode;
9784 myLastCreatedNodes.Append( aNewNode );
9788 // Create map of new nodes for modified elements
9790 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9792 std::list< int >::const_iterator anElemIter;
9793 for ( anElemIter = theListOfModifiedElems.begin();
9794 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9796 int aCurr = *anElemIter;
9797 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9801 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9803 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9805 while ( anIter->more() )
9807 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9808 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9810 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9811 aNodeArr[ ind++ ] = aNewNode;
9814 aNodeArr[ ind++ ] = aCurrNode;
9816 anElemToNodes[ anElem ] = aNodeArr;
9819 // Change nodes of elements
9821 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9822 anElemToNodesIter = anElemToNodes.begin();
9823 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9825 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9826 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9829 MESSAGE("ChangeElementNodes");
9830 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9839 //================================================================================
9841 \brief Check if element located inside shape
9842 \return TRUE if IN or ON shape, FALSE otherwise
9844 //================================================================================
9846 template<class Classifier>
9847 bool isInside(const SMDS_MeshElement* theElem,
9848 Classifier& theClassifier,
9849 const double theTol)
9851 gp_XYZ centerXYZ (0, 0, 0);
9852 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9853 while (aNodeItr->more())
9854 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
9856 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9857 theClassifier.Perform(aPnt, theTol);
9858 TopAbs_State aState = theClassifier.State();
9859 return (aState == TopAbs_IN || aState == TopAbs_ON );
9862 //================================================================================
9864 * \brief Classifier of the 3D point on the TopoDS_Face
9865 * with interaface suitable for isInside()
9867 //================================================================================
9869 struct _FaceClassifier
9871 Extrema_ExtPS _extremum;
9872 BRepAdaptor_Surface _surface;
9873 TopAbs_State _state;
9875 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9877 _extremum.Initialize( _surface,
9878 _surface.FirstUParameter(), _surface.LastUParameter(),
9879 _surface.FirstVParameter(), _surface.LastVParameter(),
9880 _surface.Tolerance(), _surface.Tolerance() );
9882 void Perform(const gp_Pnt& aPnt, double theTol)
9884 _state = TopAbs_OUT;
9885 _extremum.Perform(aPnt);
9886 if ( _extremum.IsDone() )
9887 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9888 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
9889 _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9891 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9894 TopAbs_State State() const
9901 //================================================================================
9903 \brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
9904 This method is the first step of DoubleNodeElemGroupsInRegion.
9905 \param theElems - list of groups of elements (edges or faces) to be replicated
9906 \param theNodesNot - list of groups of nodes not to replicated
9907 \param theShape - shape to detect affected elements (element which geometric center
9908 located on or inside shape). If the shape is null, detection is done on faces orientations
9909 (select elements with a gravity center on the side given by faces normals).
9910 This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations.
9911 The replicated nodes should be associated to affected elements.
9912 \return groups of affected elements
9913 \sa DoubleNodeElemGroupsInRegion()
9915 //================================================================================
9917 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
9918 const TIDSortedElemSet& theNodesNot,
9919 const TopoDS_Shape& theShape,
9920 TIDSortedElemSet& theAffectedElems)
9922 if ( theShape.IsNull() )
9924 std::set<const SMDS_MeshNode*> alreadyCheckedNodes;
9925 std::set<const SMDS_MeshElement*> alreadyCheckedElems;
9926 std::set<const SMDS_MeshElement*> edgesToCheck;
9927 alreadyCheckedNodes.clear();
9928 alreadyCheckedElems.clear();
9929 edgesToCheck.clear();
9931 // --- iterates on elements to be replicated and get elements by back references from their nodes
9933 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9935 for ( ; elemItr != theElems.end(); ++elemItr )
9937 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9938 if (!anElem || (anElem->GetType() != SMDSAbs_Face))
9941 SMESH_MeshAlgos::FaceNormal( anElem, normal, /*normalized=*/true );
9942 MESSAGE("element " << ielem++ << " normal " << normal.X() << " " << normal.Y() << " " << normal.Z());
9943 std::set<const SMDS_MeshNode*> nodesElem;
9945 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9946 while ( nodeItr->more() )
9948 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9949 nodesElem.insert(aNode);
9951 std::set<const SMDS_MeshNode*>::iterator nodit = nodesElem.begin();
9952 for (; nodit != nodesElem.end(); nodit++)
9955 const SMDS_MeshNode* aNode = *nodit;
9956 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9958 if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end())
9960 alreadyCheckedNodes.insert(aNode);
9961 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9962 while ( backElemItr->more() )
9964 MESSAGE(" backelem ");
9965 const SMDS_MeshElement* curElem = backElemItr->next();
9966 if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end())
9968 if (theElems.find(curElem) != theElems.end())
9970 alreadyCheckedElems.insert(curElem);
9971 double x=0, y=0, z=0;
9973 SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator();
9974 while ( nodeItr2->more() )
9976 const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next());
9977 x += anotherNode->X();
9978 y += anotherNode->Y();
9979 z += anotherNode->Z();
9983 p.SetCoord( x/nb -aNode->X(),
9986 MESSAGE(" check " << p.X() << " " << p.Y() << " " << p.Z());
9989 MESSAGE(" --- inserted")
9990 theAffectedElems.insert( curElem );
9992 else if (curElem->GetType() == SMDSAbs_Edge)
9993 edgesToCheck.insert(curElem);
9997 // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes)
9998 std::set<const SMDS_MeshElement*>::iterator eit = edgesToCheck.begin();
9999 for( ; eit != edgesToCheck.end(); eit++)
10001 bool onside = true;
10002 const SMDS_MeshElement* anEdge = *eit;
10003 SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator();
10004 while ( nodeItr->more() )
10006 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10007 if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end())
10015 MESSAGE(" --- edge onside inserted")
10016 theAffectedElems.insert(anEdge);
10022 const double aTol = Precision::Confusion();
10023 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10024 auto_ptr<_FaceClassifier> aFaceClassifier;
10025 if ( theShape.ShapeType() == TopAbs_SOLID )
10027 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10028 bsc3d->PerformInfinitePoint(aTol);
10030 else if (theShape.ShapeType() == TopAbs_FACE )
10032 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10035 // iterates on indicated elements and get elements by back references from their nodes
10036 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10038 for ( ; elemItr != theElems.end(); ++elemItr )
10040 MESSAGE("element " << ielem++);
10041 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10044 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10045 while ( nodeItr->more() )
10047 MESSAGE(" noeud ");
10048 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10049 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10051 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10052 while ( backElemItr->more() )
10054 MESSAGE(" backelem ");
10055 const SMDS_MeshElement* curElem = backElemItr->next();
10056 if ( curElem && theElems.find(curElem) == theElems.end() &&
10058 isInside( curElem, *bsc3d, aTol ) :
10059 isInside( curElem, *aFaceClassifier, aTol )))
10060 theAffectedElems.insert( curElem );
10068 //================================================================================
10070 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10071 \param theElems - group of of elements (edges or faces) to be replicated
10072 \param theNodesNot - group of nodes not to replicate
10073 \param theShape - shape to detect affected elements (element which geometric center
10074 located on or inside shape).
10075 The replicated nodes should be associated to affected elements.
10076 \return TRUE if operation has been completed successfully, FALSE otherwise
10078 //================================================================================
10080 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10081 const TIDSortedElemSet& theNodesNot,
10082 const TopoDS_Shape& theShape )
10084 if ( theShape.IsNull() )
10087 const double aTol = Precision::Confusion();
10088 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10089 auto_ptr<_FaceClassifier> aFaceClassifier;
10090 if ( theShape.ShapeType() == TopAbs_SOLID )
10092 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10093 bsc3d->PerformInfinitePoint(aTol);
10095 else if (theShape.ShapeType() == TopAbs_FACE )
10097 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10100 // iterates on indicated elements and get elements by back references from their nodes
10101 TIDSortedElemSet anAffected;
10102 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10103 for ( ; elemItr != theElems.end(); ++elemItr )
10105 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10109 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10110 while ( nodeItr->more() )
10112 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10113 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10115 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10116 while ( backElemItr->more() )
10118 const SMDS_MeshElement* curElem = backElemItr->next();
10119 if ( curElem && theElems.find(curElem) == theElems.end() &&
10121 isInside( curElem, *bsc3d, aTol ) :
10122 isInside( curElem, *aFaceClassifier, aTol )))
10123 anAffected.insert( curElem );
10127 return DoubleNodes( theElems, theNodesNot, anAffected );
10131 * \brief compute an oriented angle between two planes defined by four points.
10132 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10133 * @param p0 base of the rotation axe
10134 * @param p1 extremity of the rotation axe
10135 * @param g1 belongs to the first plane
10136 * @param g2 belongs to the second plane
10138 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10140 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10141 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10142 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10143 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10144 gp_Vec vref(p0, p1);
10147 gp_Vec n1 = vref.Crossed(v1);
10148 gp_Vec n2 = vref.Crossed(v2);
10149 return n2.AngleWithRef(n1, vref);
10153 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10154 * The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
10155 * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
10156 * Triangles are transformed into prisms, and quadrangles into hexahedrons.
10157 * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
10158 * 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.
10159 * 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.
10160 * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
10161 * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
10162 * @param theElems - list of groups of volumes, where a group of volume is a set of
10163 * SMDS_MeshElements sorted by Id.
10164 * @param createJointElems - if TRUE, create the elements
10165 * @return TRUE if operation has been completed successfully, FALSE otherwise
10167 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10168 bool createJointElems)
10170 MESSAGE("----------------------------------------------");
10171 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10172 MESSAGE("----------------------------------------------");
10174 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10175 meshDS->BuildDownWardConnectivity(true);
10177 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10179 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10180 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10181 // build the list of nodes shared by 2 or more domains, with their domain indexes
10183 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10184 std::map<int,int>celldom; // cell vtkId --> domain
10185 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10186 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10187 faceDomains.clear();
10189 cellDomains.clear();
10190 nodeDomains.clear();
10191 std::map<int,int> emptyMap;
10192 std::set<int> emptySet;
10195 MESSAGE(".. Number of domains :"<<theElems.size());
10197 // Check if the domains do not share an element
10198 for (int idom = 0; idom < theElems.size()-1; idom++)
10200 // MESSAGE("... Check of domain #" << idom);
10201 const TIDSortedElemSet& domain = theElems[idom];
10202 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10203 for (; elemItr != domain.end(); ++elemItr)
10205 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10206 int idombisdeb = idom + 1 ;
10207 for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
10209 const TIDSortedElemSet& domainbis = theElems[idombis];
10210 if ( domainbis.count(anElem) )
10212 MESSAGE(".... Domain #" << idom);
10213 MESSAGE(".... Domain #" << idombis);
10214 throw SALOME_Exception("The domains are not disjoint.");
10221 for (int idom = 0; idom < theElems.size(); idom++)
10224 // --- build a map (face to duplicate --> volume to modify)
10225 // with all the faces shared by 2 domains (group of elements)
10226 // and corresponding volume of this domain, for each shared face.
10227 // a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
10229 MESSAGE("... Neighbors of domain #" << idom);
10230 const TIDSortedElemSet& domain = theElems[idom];
10231 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10232 for (; elemItr != domain.end(); ++elemItr)
10234 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10237 int vtkId = anElem->getVtkId();
10238 //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID());
10239 int neighborsVtkIds[NBMAXNEIGHBORS];
10240 int downIds[NBMAXNEIGHBORS];
10241 unsigned char downTypes[NBMAXNEIGHBORS];
10242 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10243 for (int n = 0; n < nbNeighbors; n++)
10245 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10246 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10247 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10250 for (int idombis = 0; idombis < theElems.size(); idombis++) // check if the neighbor belongs to another domain of the list
10252 // MESSAGE("Domain " << idombis);
10253 const TIDSortedElemSet& domainbis = theElems[idombis];
10254 if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
10256 if ( ok ) // the characteristics of the face is stored
10258 DownIdType face(downIds[n], downTypes[n]);
10259 if (!faceDomains.count(face))
10260 faceDomains[face] = emptyMap; // create an empty entry for face
10261 if (!faceDomains[face].count(idom))
10263 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10264 celldom[vtkId] = idom;
10265 //MESSAGE(" cell with a border " << vtkId << " domain " << idom);
10273 //MESSAGE("Number of shared faces " << faceDomains.size());
10274 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10276 // --- explore the shared faces domain by domain,
10277 // explore the nodes of the face and see if they belong to a cell in the domain,
10278 // which has only a node or an edge on the border (not a shared face)
10280 for (int idomain = 0; idomain < theElems.size(); idomain++)
10282 //MESSAGE("Domain " << idomain);
10283 const TIDSortedElemSet& domain = theElems[idomain];
10284 itface = faceDomains.begin();
10285 for (; itface != faceDomains.end(); ++itface)
10287 std::map<int, int> domvol = itface->second;
10288 if (!domvol.count(idomain))
10290 DownIdType face = itface->first;
10291 //MESSAGE(" --- face " << face.cellId);
10292 std::set<int> oldNodes;
10294 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10295 std::set<int>::iterator itn = oldNodes.begin();
10296 for (; itn != oldNodes.end(); ++itn)
10299 //MESSAGE(" node " << oldId);
10300 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10301 for (int i=0; i<l.ncells; i++)
10303 int vtkId = l.cells[i];
10304 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10305 if (!domain.count(anElem))
10307 int vtkType = grid->GetCellType(vtkId);
10308 int downId = grid->CellIdToDownId(vtkId);
10311 MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10312 continue; // not OK at this stage of the algorithm:
10313 //no cells created after BuildDownWardConnectivity
10315 DownIdType aCell(downId, vtkType);
10316 if (!cellDomains.count(aCell))
10317 cellDomains[aCell] = emptyMap; // create an empty entry for cell
10318 cellDomains[aCell][idomain] = vtkId;
10319 celldom[vtkId] = idomain;
10320 //MESSAGE(" cell " << vtkId << " domain " << idomain);
10326 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10327 // for each shared face, get the nodes
10328 // for each node, for each domain of the face, create a clone of the node
10330 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10331 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10332 // the value is the ordered domain ids. (more than 4 domains not taken into account)
10334 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10335 std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10336 std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10338 MESSAGE(".. Duplication of the nodes");
10339 for (int idomain = 0; idomain < theElems.size(); idomain++)
10341 itface = faceDomains.begin();
10342 for (; itface != faceDomains.end(); ++itface)
10344 std::map<int, int> domvol = itface->second;
10345 if (!domvol.count(idomain))
10347 DownIdType face = itface->first;
10348 //MESSAGE(" --- face " << face.cellId);
10349 std::set<int> oldNodes;
10351 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10352 std::set<int>::iterator itn = oldNodes.begin();
10353 for (; itn != oldNodes.end(); ++itn)
10356 //MESSAGE("-+-+-a node " << oldId);
10357 if (!nodeDomains.count(oldId))
10358 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10359 if (nodeDomains[oldId].empty())
10361 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10362 //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain);
10364 std::map<int, int>::iterator itdom = domvol.begin();
10365 for (; itdom != domvol.end(); ++itdom)
10367 int idom = itdom->first;
10368 //MESSAGE(" domain " << idom);
10369 if (!nodeDomains[oldId].count(idom)) // --- node to clone
10371 if (nodeDomains[oldId].size() >= 2) // a multiple node
10373 vector<int> orderedDoms;
10374 //MESSAGE("multiple node " << oldId);
10375 if (mutipleNodes.count(oldId))
10376 orderedDoms = mutipleNodes[oldId];
10379 map<int,int>::iterator it = nodeDomains[oldId].begin();
10380 for (; it != nodeDomains[oldId].end(); ++it)
10381 orderedDoms.push_back(it->first);
10383 orderedDoms.push_back(idom); // TODO order ==> push_front or back
10384 //stringstream txt;
10385 //for (int i=0; i<orderedDoms.size(); i++)
10386 // txt << orderedDoms[i] << " ";
10387 //MESSAGE("orderedDoms " << txt.str());
10388 mutipleNodes[oldId] = orderedDoms;
10390 double *coords = grid->GetPoint(oldId);
10391 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10392 int newId = newNode->getVtkId();
10393 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10394 //MESSAGE("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
10401 MESSAGE(".. Creation of elements");
10402 for (int idomain = 0; idomain < theElems.size(); idomain++)
10404 itface = faceDomains.begin();
10405 for (; itface != faceDomains.end(); ++itface)
10407 std::map<int, int> domvol = itface->second;
10408 if (!domvol.count(idomain))
10410 DownIdType face = itface->first;
10411 //MESSAGE(" --- face " << face.cellId);
10412 std::set<int> oldNodes;
10414 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10415 int nbMultipleNodes = 0;
10416 std::set<int>::iterator itn = oldNodes.begin();
10417 for (; itn != oldNodes.end(); ++itn)
10420 if (mutipleNodes.count(oldId))
10423 if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
10425 //MESSAGE("multiple Nodes detected on a shared face");
10426 int downId = itface->first.cellId;
10427 unsigned char cellType = itface->first.cellType;
10428 // --- shared edge or shared face ?
10429 if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10432 int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10433 for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10434 if (mutipleNodes.count(nodes[i]))
10435 if (!mutipleNodesToFace.count(nodes[i]))
10436 mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10438 else // shared face (between two volumes)
10440 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10441 const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10442 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10443 for (int ie =0; ie < nbEdges; ie++)
10446 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10447 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10449 vector<int> vn0 = mutipleNodes[nodes[0]];
10450 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10452 for (int i0 = 0; i0 < vn0.size(); i0++)
10453 for (int i1 = 0; i1 < vn1.size(); i1++)
10454 if (vn0[i0] == vn1[i1])
10455 doms.push_back(vn0[i0]);
10456 if (doms.size() >2)
10458 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10459 double *coords = grid->GetPoint(nodes[0]);
10460 gp_Pnt p0(coords[0], coords[1], coords[2]);
10461 coords = grid->GetPoint(nodes[nbNodes - 1]);
10462 gp_Pnt p1(coords[0], coords[1], coords[2]);
10464 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
10465 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10466 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10467 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10468 for (int id=0; id < doms.size(); id++)
10470 int idom = doms[id];
10471 for (int ivol=0; ivol<nbvol; ivol++)
10473 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10474 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10475 if (theElems[idom].count(elem))
10477 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10478 domvol[idom] = svol;
10479 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
10481 vtkIdType npts = 0;
10482 vtkIdType* pts = 0;
10483 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10484 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10487 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10488 angleDom[idom] = 0;
10492 gp_Pnt g(values[0], values[1], values[2]);
10493 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10494 //MESSAGE(" angle=" << angleDom[idom]);
10500 map<double, int> sortedDom; // sort domains by angle
10501 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10502 sortedDom[ia->second] = ia->first;
10503 vector<int> vnodes;
10505 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10507 vdom.push_back(ib->second);
10508 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
10510 for (int ino = 0; ino < nbNodes; ino++)
10511 vnodes.push_back(nodes[ino]);
10512 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10521 // --- iterate on shared faces (volumes to modify, face to extrude)
10522 // get node id's of the face (id SMDS = id VTK)
10523 // create flat element with old and new nodes if requested
10525 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10526 // (domain1 X domain2) = domain1 + MAXINT*domain2
10528 std::map<int, std::map<long,int> > nodeQuadDomains;
10529 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10531 MESSAGE(".. Creation of elements: simple junction");
10532 if (createJointElems)
10535 string joints2DName = "joints2D";
10536 mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
10537 SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
10538 string joints3DName = "joints3D";
10539 mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
10540 SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
10542 itface = faceDomains.begin();
10543 for (; itface != faceDomains.end(); ++itface)
10545 DownIdType face = itface->first;
10546 std::set<int> oldNodes;
10547 std::set<int>::iterator itn;
10549 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10551 std::map<int, int> domvol = itface->second;
10552 std::map<int, int>::iterator itdom = domvol.begin();
10553 int dom1 = itdom->first;
10554 int vtkVolId = itdom->second;
10556 int dom2 = itdom->first;
10557 SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
10559 stringstream grpname;
10562 grpname << dom1 << "_" << dom2;
10564 grpname << dom2 << "_" << dom1;
10565 string namegrp = grpname.str();
10566 if (!mapOfJunctionGroups.count(namegrp))
10567 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
10568 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10570 sgrp->Add(vol->GetID());
10571 if (vol->GetType() == SMDSAbs_Volume)
10572 joints3DGrp->Add(vol->GetID());
10573 else if (vol->GetType() == SMDSAbs_Face)
10574 joints2DGrp->Add(vol->GetID());
10578 // --- create volumes on multiple domain intersection if requested
10579 // iterate on mutipleNodesToFace
10580 // iterate on edgesMultiDomains
10582 MESSAGE(".. Creation of elements: multiple junction");
10583 if (createJointElems)
10585 // --- iterate on mutipleNodesToFace
10587 std::map<int, std::vector<int> >::iterator itn = mutipleNodesToFace.begin();
10588 for (; itn != mutipleNodesToFace.end(); ++itn)
10590 int node = itn->first;
10591 vector<int> orderDom = itn->second;
10592 vector<vtkIdType> orderedNodes;
10593 for (int idom = 0; idom <orderDom.size(); idom++)
10594 orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
10595 SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
10597 stringstream grpname;
10599 grpname << 0 << "_" << 0;
10601 string namegrp = grpname.str();
10602 if (!mapOfJunctionGroups.count(namegrp))
10603 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
10604 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10606 sgrp->Add(face->GetID());
10609 // --- iterate on edgesMultiDomains
10611 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
10612 for (; ite != edgesMultiDomains.end(); ++ite)
10614 vector<int> nodes = ite->first;
10615 vector<int> orderDom = ite->second;
10616 vector<vtkIdType> orderedNodes;
10617 if (nodes.size() == 2)
10619 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
10620 for (int ino=0; ino < nodes.size(); ino++)
10621 if (orderDom.size() == 3)
10622 for (int idom = 0; idom <orderDom.size(); idom++)
10623 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10625 for (int idom = orderDom.size()-1; idom >=0; idom--)
10626 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10627 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
10630 string namegrp = "jointsMultiples";
10631 if (!mapOfJunctionGroups.count(namegrp))
10632 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10633 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10635 sgrp->Add(vol->GetID());
10639 INFOS("Quadratic multiple joints not implemented");
10640 // TODO quadratic nodes
10645 // --- list the explicit faces and edges of the mesh that need to be modified,
10646 // i.e. faces and edges built with one or more duplicated nodes.
10647 // associate these faces or edges to their corresponding domain.
10648 // only the first domain found is kept when a face or edge is shared
10650 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
10651 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
10652 faceOrEdgeDom.clear();
10655 MESSAGE(".. Modification of elements");
10656 for (int idomain = 0; idomain < theElems.size(); idomain++)
10658 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
10659 for (; itnod != nodeDomains.end(); ++itnod)
10661 int oldId = itnod->first;
10662 //MESSAGE(" node " << oldId);
10663 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10664 for (int i = 0; i < l.ncells; i++)
10666 int vtkId = l.cells[i];
10667 int vtkType = grid->GetCellType(vtkId);
10668 int downId = grid->CellIdToDownId(vtkId);
10670 continue; // new cells: not to be modified
10671 DownIdType aCell(downId, vtkType);
10672 int volParents[1000];
10673 int nbvol = grid->GetParentVolumes(volParents, vtkId);
10674 for (int j = 0; j < nbvol; j++)
10675 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
10676 if (!feDom.count(vtkId))
10678 feDom[vtkId] = idomain;
10679 faceOrEdgeDom[aCell] = emptyMap;
10680 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
10681 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
10682 // << " type " << vtkType << " downId " << downId);
10688 // --- iterate on shared faces (volumes to modify, face to extrude)
10689 // get node id's of the face
10690 // replace old nodes by new nodes in volumes, and update inverse connectivity
10692 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
10693 for (int m=0; m<3; m++)
10695 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
10696 itface = (*amap).begin();
10697 for (; itface != (*amap).end(); ++itface)
10699 DownIdType face = itface->first;
10700 std::set<int> oldNodes;
10701 std::set<int>::iterator itn;
10703 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10704 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
10705 std::map<int, int> localClonedNodeIds;
10707 std::map<int, int> domvol = itface->second;
10708 std::map<int, int>::iterator itdom = domvol.begin();
10709 for (; itdom != domvol.end(); ++itdom)
10711 int idom = itdom->first;
10712 int vtkVolId = itdom->second;
10713 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
10714 localClonedNodeIds.clear();
10715 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10718 if (nodeDomains[oldId].count(idom))
10720 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10721 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
10724 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10729 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
10730 grid->BuildLinks();
10738 * \brief Double nodes on some external faces and create flat elements.
10739 * Flat elements are mainly used by some types of mechanic calculations.
10741 * Each group of the list must be constituted of faces.
10742 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10743 * @param theElems - list of groups of faces, where a group of faces is a set of
10744 * SMDS_MeshElements sorted by Id.
10745 * @return TRUE if operation has been completed successfully, FALSE otherwise
10747 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
10749 MESSAGE("-------------------------------------------------");
10750 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
10751 MESSAGE("-------------------------------------------------");
10753 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10755 // --- For each group of faces
10756 // duplicate the nodes, create a flat element based on the face
10757 // replace the nodes of the faces by their clones
10759 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
10760 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
10761 clonedNodes.clear();
10762 intermediateNodes.clear();
10763 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10764 mapOfJunctionGroups.clear();
10766 for (int idom = 0; idom < theElems.size(); idom++)
10768 const TIDSortedElemSet& domain = theElems[idom];
10769 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10770 for (; elemItr != domain.end(); ++elemItr)
10772 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10773 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
10776 // MESSAGE("aFace=" << aFace->GetID());
10777 bool isQuad = aFace->IsQuadratic();
10778 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
10780 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
10782 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
10783 while (nodeIt->more())
10785 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
10786 bool isMedium = isQuad && (aFace->IsMediumNode(node));
10788 ln2.push_back(node);
10790 ln0.push_back(node);
10792 const SMDS_MeshNode* clone = 0;
10793 if (!clonedNodes.count(node))
10795 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
10796 clonedNodes[node] = clone;
10799 clone = clonedNodes[node];
10802 ln3.push_back(clone);
10804 ln1.push_back(clone);
10806 const SMDS_MeshNode* inter = 0;
10807 if (isQuad && (!isMedium))
10809 if (!intermediateNodes.count(node))
10811 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
10812 intermediateNodes[node] = inter;
10815 inter = intermediateNodes[node];
10816 ln4.push_back(inter);
10820 // --- extrude the face
10822 vector<const SMDS_MeshNode*> ln;
10823 SMDS_MeshVolume* vol = 0;
10824 vtkIdType aType = aFace->GetVtkType();
10828 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
10829 // MESSAGE("vol prism " << vol->GetID());
10830 ln.push_back(ln1[0]);
10831 ln.push_back(ln1[1]);
10832 ln.push_back(ln1[2]);
10835 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
10836 // MESSAGE("vol hexa " << vol->GetID());
10837 ln.push_back(ln1[0]);
10838 ln.push_back(ln1[1]);
10839 ln.push_back(ln1[2]);
10840 ln.push_back(ln1[3]);
10842 case VTK_QUADRATIC_TRIANGLE:
10843 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
10844 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
10845 // MESSAGE("vol quad prism " << vol->GetID());
10846 ln.push_back(ln1[0]);
10847 ln.push_back(ln1[1]);
10848 ln.push_back(ln1[2]);
10849 ln.push_back(ln3[0]);
10850 ln.push_back(ln3[1]);
10851 ln.push_back(ln3[2]);
10853 case VTK_QUADRATIC_QUAD:
10854 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
10855 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
10856 // ln4[0], ln4[1], ln4[2], ln4[3]);
10857 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
10858 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
10859 ln4[0], ln4[1], ln4[2], ln4[3]);
10860 // MESSAGE("vol quad hexa " << vol->GetID());
10861 ln.push_back(ln1[0]);
10862 ln.push_back(ln1[1]);
10863 ln.push_back(ln1[2]);
10864 ln.push_back(ln1[3]);
10865 ln.push_back(ln3[0]);
10866 ln.push_back(ln3[1]);
10867 ln.push_back(ln3[2]);
10868 ln.push_back(ln3[3]);
10878 stringstream grpname;
10882 string namegrp = grpname.str();
10883 if (!mapOfJunctionGroups.count(namegrp))
10884 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10885 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10887 sgrp->Add(vol->GetID());
10890 // --- modify the face
10892 aFace->ChangeNodes(&ln[0], ln.size());
10899 * \brief identify all the elements around a geom shape, get the faces delimiting the hole
10900 * Build groups of volume to remove, groups of faces to replace on the skin of the object,
10901 * groups of faces to remove inside the object, (idem edges).
10902 * Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
10904 void SMESH_MeshEditor::CreateHoleSkin(double radius,
10905 const TopoDS_Shape& theShape,
10906 SMESH_NodeSearcher* theNodeSearcher,
10907 const char* groupName,
10908 std::vector<double>& nodesCoords,
10909 std::vector<std::vector<int> >& listOfListOfNodes)
10911 MESSAGE("--------------------------------");
10912 MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
10913 MESSAGE("--------------------------------");
10915 // --- zone of volumes to remove is given :
10916 // 1 either by a geom shape (one or more vertices) and a radius,
10917 // 2 either by a group of nodes (representative of the shape)to use with the radius,
10918 // 3 either by a group of nodes where all the elements build on one of this nodes are to remove,
10919 // In the case 2, the group of nodes is an external group of nodes from another mesh,
10920 // In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
10921 // defined by it's name.
10923 SMESHDS_GroupBase* groupDS = 0;
10924 SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
10925 while ( groupIt->more() )
10928 SMESH_Group * group = groupIt->next();
10929 if ( !group ) continue;
10930 groupDS = group->GetGroupDS();
10931 if ( !groupDS || groupDS->IsEmpty() ) continue;
10932 std::string grpName = group->GetName();
10933 //MESSAGE("grpName=" << grpName);
10934 if (grpName == groupName)
10940 bool isNodeGroup = false;
10941 bool isNodeCoords = false;
10944 if (groupDS->GetType() != SMDSAbs_Node)
10946 isNodeGroup = true; // a group of nodes exists and it is in this mesh
10949 if (nodesCoords.size() > 0)
10950 isNodeCoords = true; // a list o nodes given by their coordinates
10951 //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
10953 // --- define groups to build
10955 int idg; // --- group of SMDS volumes
10956 string grpvName = groupName;
10957 grpvName += "_vol";
10958 SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
10961 MESSAGE("group not created " << grpvName);
10964 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
10966 int idgs; // --- group of SMDS faces on the skin
10967 string grpsName = groupName;
10968 grpsName += "_skin";
10969 SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
10972 MESSAGE("group not created " << grpsName);
10975 SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
10977 int idgi; // --- group of SMDS faces internal (several shapes)
10978 string grpiName = groupName;
10979 grpiName += "_internalFaces";
10980 SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
10983 MESSAGE("group not created " << grpiName);
10986 SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
10988 int idgei; // --- group of SMDS faces internal (several shapes)
10989 string grpeiName = groupName;
10990 grpeiName += "_internalEdges";
10991 SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
10994 MESSAGE("group not created " << grpeiName);
10997 SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
10999 // --- build downward connectivity
11001 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11002 meshDS->BuildDownWardConnectivity(true);
11003 SMDS_UnstructuredGrid* grid = meshDS->getGrid();
11005 // --- set of volumes detected inside
11007 std::set<int> setOfInsideVol;
11008 std::set<int> setOfVolToCheck;
11010 std::vector<gp_Pnt> gpnts;
11013 if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
11015 MESSAGE("group of nodes provided");
11016 SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
11017 while ( elemIt->more() )
11019 const SMDS_MeshElement* elem = elemIt->next();
11022 const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
11025 SMDS_MeshElement* vol = 0;
11026 SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
11027 while (volItr->more())
11029 vol = (SMDS_MeshElement*)volItr->next();
11030 setOfInsideVol.insert(vol->getVtkId());
11031 sgrp->Add(vol->GetID());
11035 else if (isNodeCoords)
11037 MESSAGE("list of nodes coordinates provided");
11040 while (i < nodesCoords.size()-2)
11042 double x = nodesCoords[i++];
11043 double y = nodesCoords[i++];
11044 double z = nodesCoords[i++];
11045 gp_Pnt p = gp_Pnt(x, y ,z);
11046 gpnts.push_back(p);
11047 MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
11051 else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
11053 MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
11054 TopTools_IndexedMapOfShape vertexMap;
11055 TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
11056 gp_Pnt p = gp_Pnt(0,0,0);
11057 if (vertexMap.Extent() < 1)
11060 for ( int i = 1; i <= vertexMap.Extent(); ++i )
11062 const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
11063 p = BRep_Tool::Pnt(vertex);
11064 gpnts.push_back(p);
11065 MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
11069 if (gpnts.size() > 0)
11072 const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
11074 nodeId = startNode->GetID();
11075 MESSAGE("nodeId " << nodeId);
11077 double radius2 = radius*radius;
11078 MESSAGE("radius2 " << radius2);
11080 // --- volumes on start node
11082 setOfVolToCheck.clear();
11083 SMDS_MeshElement* startVol = 0;
11084 SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
11085 while (volItr->more())
11087 startVol = (SMDS_MeshElement*)volItr->next();
11088 setOfVolToCheck.insert(startVol->getVtkId());
11090 if (setOfVolToCheck.empty())
11092 MESSAGE("No volumes found");
11096 // --- starting with central volumes then their neighbors, check if they are inside
11097 // or outside the domain, until no more new neighbor volume is inside.
11098 // Fill the group of inside volumes
11100 std::map<int, double> mapOfNodeDistance2;
11101 mapOfNodeDistance2.clear();
11102 std::set<int> setOfOutsideVol;
11103 while (!setOfVolToCheck.empty())
11105 std::set<int>::iterator it = setOfVolToCheck.begin();
11107 MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11108 bool volInside = false;
11109 vtkIdType npts = 0;
11110 vtkIdType* pts = 0;
11111 grid->GetCellPoints(vtkId, npts, pts);
11112 for (int i=0; i<npts; i++)
11114 double distance2 = 0;
11115 if (mapOfNodeDistance2.count(pts[i]))
11117 distance2 = mapOfNodeDistance2[pts[i]];
11118 MESSAGE("point " << pts[i] << " distance2 " << distance2);
11122 double *coords = grid->GetPoint(pts[i]);
11123 gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
11125 for (int j=0; j<gpnts.size(); j++)
11127 double d2 = aPoint.SquareDistance(gpnts[j]);
11128 if (d2 < distance2)
11131 if (distance2 < radius2)
11135 mapOfNodeDistance2[pts[i]] = distance2;
11136 MESSAGE(" point " << pts[i] << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " << coords[2]);
11138 if (distance2 < radius2)
11140 volInside = true; // one or more nodes inside the domain
11141 sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11147 setOfInsideVol.insert(vtkId);
11148 MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11149 int neighborsVtkIds[NBMAXNEIGHBORS];
11150 int downIds[NBMAXNEIGHBORS];
11151 unsigned char downTypes[NBMAXNEIGHBORS];
11152 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11153 for (int n = 0; n < nbNeighbors; n++)
11154 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
11155 setOfVolToCheck.insert(neighborsVtkIds[n]);
11159 setOfOutsideVol.insert(vtkId);
11160 MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11162 setOfVolToCheck.erase(vtkId);
11166 // --- for outside hexahedrons, check if they have more than one neighbor volume inside
11167 // If yes, add the volume to the inside set
11169 bool addedInside = true;
11170 std::set<int> setOfVolToReCheck;
11171 while (addedInside)
11173 MESSAGE(" --------------------------- re check");
11174 addedInside = false;
11175 std::set<int>::iterator itv = setOfInsideVol.begin();
11176 for (; itv != setOfInsideVol.end(); ++itv)
11179 int neighborsVtkIds[NBMAXNEIGHBORS];
11180 int downIds[NBMAXNEIGHBORS];
11181 unsigned char downTypes[NBMAXNEIGHBORS];
11182 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11183 for (int n = 0; n < nbNeighbors; n++)
11184 if (!setOfInsideVol.count(neighborsVtkIds[n]))
11185 setOfVolToReCheck.insert(neighborsVtkIds[n]);
11187 setOfVolToCheck = setOfVolToReCheck;
11188 setOfVolToReCheck.clear();
11189 while (!setOfVolToCheck.empty())
11191 std::set<int>::iterator it = setOfVolToCheck.begin();
11193 if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
11195 MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11196 int countInside = 0;
11197 int neighborsVtkIds[NBMAXNEIGHBORS];
11198 int downIds[NBMAXNEIGHBORS];
11199 unsigned char downTypes[NBMAXNEIGHBORS];
11200 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11201 for (int n = 0; n < nbNeighbors; n++)
11202 if (setOfInsideVol.count(neighborsVtkIds[n]))
11204 MESSAGE("countInside " << countInside);
11205 if (countInside > 1)
11207 MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11208 setOfInsideVol.insert(vtkId);
11209 sgrp->Add(meshDS->fromVtkToSmds(vtkId));
11210 addedInside = true;
11213 setOfVolToReCheck.insert(vtkId);
11215 setOfVolToCheck.erase(vtkId);
11219 // --- map of Downward faces at the boundary, inside the global volume
11220 // map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
11221 // fill group of SMDS faces inside the volume (when several volume shapes)
11222 // fill group of SMDS faces on the skin of the global volume (if skin)
11224 std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
11225 std::map<DownIdType, int, DownIdCompare> skinFaces; // faces on the skin of the global volume --> corresponding cell
11226 std::set<int>::iterator it = setOfInsideVol.begin();
11227 for (; it != setOfInsideVol.end(); ++it)
11230 //MESSAGE(" vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
11231 int neighborsVtkIds[NBMAXNEIGHBORS];
11232 int downIds[NBMAXNEIGHBORS];
11233 unsigned char downTypes[NBMAXNEIGHBORS];
11234 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
11235 for (int n = 0; n < nbNeighbors; n++)
11237 int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
11238 if (neighborDim == 3)
11240 if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
11242 DownIdType face(downIds[n], downTypes[n]);
11243 boundaryFaces[face] = vtkId;
11245 // if the face between to volumes is in the mesh, get it (internal face between shapes)
11246 int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11247 if (vtkFaceId >= 0)
11249 sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
11250 // find also the smds edges on this face
11251 int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
11252 const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
11253 const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
11254 for (int i = 0; i < nbEdges; i++)
11256 int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
11257 if (vtkEdgeId >= 0)
11258 sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
11262 else if (neighborDim == 2) // skin of the volume
11264 DownIdType face(downIds[n], downTypes[n]);
11265 skinFaces[face] = vtkId;
11266 int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
11267 if (vtkFaceId >= 0)
11268 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
11273 // --- identify the edges constituting the wire of each subshape on the skin
11274 // define polylines with the nodes of edges, equivalent to wires
11275 // project polylines on subshapes, and partition, to get geom faces
11277 std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
11278 std::set<int> emptySet;
11280 std::set<int> shapeIds;
11282 SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
11283 while (itelem->more())
11285 const SMDS_MeshElement *elem = itelem->next();
11286 int shapeId = elem->getshapeId();
11287 int vtkId = elem->getVtkId();
11288 if (!shapeIdToVtkIdSet.count(shapeId))
11290 shapeIdToVtkIdSet[shapeId] = emptySet;
11291 shapeIds.insert(shapeId);
11293 shapeIdToVtkIdSet[shapeId].insert(vtkId);
11296 std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
11297 std::set<DownIdType, DownIdCompare> emptyEdges;
11298 emptyEdges.clear();
11300 std::map<int, std::set<int> >::iterator itShape = shapeIdToVtkIdSet.begin();
11301 for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
11303 int shapeId = itShape->first;
11304 MESSAGE(" --- Shape ID --- "<< shapeId);
11305 shapeIdToEdges[shapeId] = emptyEdges;
11307 std::vector<int> nodesEdges;
11309 std::set<int>::iterator its = itShape->second.begin();
11310 for (; its != itShape->second.end(); ++its)
11313 MESSAGE(" " << vtkId);
11314 int neighborsVtkIds[NBMAXNEIGHBORS];
11315 int downIds[NBMAXNEIGHBORS];
11316 unsigned char downTypes[NBMAXNEIGHBORS];
11317 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11318 for (int n = 0; n < nbNeighbors; n++)
11320 if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
11322 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11323 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11324 if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
11326 DownIdType edge(downIds[n], downTypes[n]);
11327 if (!shapeIdToEdges[shapeId].count(edge))
11329 shapeIdToEdges[shapeId].insert(edge);
11331 int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
11332 nodesEdges.push_back(vtkNodeId[0]);
11333 nodesEdges.push_back(vtkNodeId[nbNodes-1]);
11334 MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
11340 std::list<int> order;
11342 if (nodesEdges.size() > 0)
11344 order.push_back(nodesEdges[0]); MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1;
11345 nodesEdges[0] = -1;
11346 order.push_back(nodesEdges[1]); MESSAGE(" --- back " << order.back()+1);
11347 nodesEdges[1] = -1; // do not reuse this edge
11351 int nodeTofind = order.back(); // try first to push back
11353 for (i = 0; i<nodesEdges.size(); i++)
11354 if (nodesEdges[i] == nodeTofind)
11356 if (i == nodesEdges.size())
11357 found = false; // no follower found on back
11360 if (i%2) // odd ==> use the previous one
11361 if (nodesEdges[i-1] < 0)
11365 order.push_back(nodesEdges[i-1]); MESSAGE(" --- back " << order.back()+1);
11366 nodesEdges[i-1] = -1;
11368 else // even ==> use the next one
11369 if (nodesEdges[i+1] < 0)
11373 order.push_back(nodesEdges[i+1]); MESSAGE(" --- back " << order.back()+1);
11374 nodesEdges[i+1] = -1;
11379 // try to push front
11381 nodeTofind = order.front(); // try to push front
11382 for (i = 0; i<nodesEdges.size(); i++)
11383 if (nodesEdges[i] == nodeTofind)
11385 if (i == nodesEdges.size())
11387 found = false; // no predecessor found on front
11390 if (i%2) // odd ==> use the previous one
11391 if (nodesEdges[i-1] < 0)
11395 order.push_front(nodesEdges[i-1]); MESSAGE(" --- front " << order.front()+1);
11396 nodesEdges[i-1] = -1;
11398 else // even ==> use the next one
11399 if (nodesEdges[i+1] < 0)
11403 order.push_front(nodesEdges[i+1]); MESSAGE(" --- front " << order.front()+1);
11404 nodesEdges[i+1] = -1;
11410 std::vector<int> nodes;
11411 nodes.push_back(shapeId);
11412 std::list<int>::iterator itl = order.begin();
11413 for (; itl != order.end(); itl++)
11415 nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
11416 MESSAGE(" ordered node " << nodes[nodes.size()-1]);
11418 listOfListOfNodes.push_back(nodes);
11421 // partition geom faces with blocFissure
11422 // mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
11423 // mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
11429 //================================================================================
11431 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11432 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11433 * \return TRUE if operation has been completed successfully, FALSE otherwise
11435 //================================================================================
11437 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11439 // iterates on volume elements and detect all free faces on them
11440 SMESHDS_Mesh* aMesh = GetMeshDS();
11443 //bool res = false;
11444 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11445 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11448 const SMDS_MeshVolume* volume = vIt->next();
11449 SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11450 vTool.SetExternalNormal();
11451 //const bool isPoly = volume->IsPoly();
11452 const int iQuad = volume->IsQuadratic();
11453 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11455 if (!vTool.IsFreeFace(iface))
11458 vector<const SMDS_MeshNode *> nodes;
11459 int nbFaceNodes = vTool.NbFaceNodes(iface);
11460 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11462 for ( ; inode < nbFaceNodes; inode += iQuad+1)
11463 nodes.push_back(faceNodes[inode]);
11464 if (iQuad) { // add medium nodes
11465 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11466 nodes.push_back(faceNodes[inode]);
11467 if ( nbFaceNodes == 9 ) // bi-quadratic quad
11468 nodes.push_back(faceNodes[8]);
11470 // add new face based on volume nodes
11471 if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11473 continue; // face already exsist
11475 AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11479 return ( nbFree==(nbExisted+nbCreated) );
11484 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11486 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11488 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11491 //================================================================================
11493 * \brief Creates missing boundary elements
11494 * \param elements - elements whose boundary is to be checked
11495 * \param dimension - defines type of boundary elements to create
11496 * \param group - a group to store created boundary elements in
11497 * \param targetMesh - a mesh to store created boundary elements in
11498 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11499 * \param toCopyExistingBoundary - if true, not only new but also pre-existing
11500 * boundary elements will be copied into the targetMesh
11501 * \param toAddExistingBondary - if true, not only new but also pre-existing
11502 * boundary elements will be added into the new group
11503 * \param aroundElements - if true, elements will be created on boundary of given
11504 * elements else, on boundary of the whole mesh.
11505 * \return nb of added boundary elements
11507 //================================================================================
11509 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11510 Bnd_Dimension dimension,
11511 SMESH_Group* group/*=0*/,
11512 SMESH_Mesh* targetMesh/*=0*/,
11513 bool toCopyElements/*=false*/,
11514 bool toCopyExistingBoundary/*=false*/,
11515 bool toAddExistingBondary/*= false*/,
11516 bool aroundElements/*= false*/)
11518 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11519 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11520 // hope that all elements are of the same type, do not check them all
11521 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11522 throw SALOME_Exception(LOCALIZED("wrong element type"));
11525 toCopyElements = toCopyExistingBoundary = false;
11527 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11528 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11529 int nbAddedBnd = 0;
11531 // editor adding present bnd elements and optionally holding elements to add to the group
11532 SMESH_MeshEditor* presentEditor;
11533 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11534 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11536 SMESH_MesherHelper helper( *myMesh );
11537 const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11538 SMDS_VolumeTool vTool;
11539 TIDSortedElemSet avoidSet;
11540 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11543 typedef vector<const SMDS_MeshNode*> TConnectivity;
11545 SMDS_ElemIteratorPtr eIt;
11546 if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11547 else eIt = elemSetIterator( elements );
11549 while (eIt->more())
11551 const SMDS_MeshElement* elem = eIt->next();
11552 const int iQuad = elem->IsQuadratic();
11554 // ------------------------------------------------------------------------------------
11555 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11556 // ------------------------------------------------------------------------------------
11557 vector<const SMDS_MeshElement*> presentBndElems;
11558 vector<TConnectivity> missingBndElems;
11559 TConnectivity nodes, elemNodes;
11560 if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11562 vTool.SetExternalNormal();
11563 const SMDS_MeshElement* otherVol = 0;
11564 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11566 if ( !vTool.IsFreeFace(iface, &otherVol) &&
11567 ( !aroundElements || elements.count( otherVol )))
11569 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11570 const int nbFaceNodes = vTool.NbFaceNodes (iface);
11571 if ( missType == SMDSAbs_Edge ) // boundary edges
11573 nodes.resize( 2+iQuad );
11574 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11576 for ( int j = 0; j < nodes.size(); ++j )
11578 if ( const SMDS_MeshElement* edge =
11579 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11580 presentBndElems.push_back( edge );
11582 missingBndElems.push_back( nodes );
11585 else // boundary face
11588 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11589 nodes.push_back( nn[inode] ); // add corner nodes
11591 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11592 nodes.push_back( nn[inode] ); // add medium nodes
11593 int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11595 nodes.push_back( vTool.GetNodes()[ iCenter ] );
11597 if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11598 SMDSAbs_Face, /*noMedium=*/false ))
11599 presentBndElems.push_back( f );
11601 missingBndElems.push_back( nodes );
11603 if ( targetMesh != myMesh )
11605 // add 1D elements on face boundary to be added to a new mesh
11606 const SMDS_MeshElement* edge;
11607 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11610 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11612 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11613 if ( edge && avoidSet.insert( edge ).second )
11614 presentBndElems.push_back( edge );
11620 else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
11622 avoidSet.clear(), avoidSet.insert( elem );
11623 elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesElemIterator() ),
11624 SMDS_MeshElement::iterator() );
11625 elemNodes.push_back( elemNodes[0] );
11626 nodes.resize( 2 + iQuad );
11627 const int nbLinks = elem->NbCornerNodes();
11628 for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
11630 nodes[0] = elemNodes[iN];
11631 nodes[1] = elemNodes[iN+1+iQuad];
11632 if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11633 continue; // not free link
11635 if ( iQuad ) nodes[2] = elemNodes[iN+1];
11636 if ( const SMDS_MeshElement* edge =
11637 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11638 presentBndElems.push_back( edge );
11640 missingBndElems.push_back( nodes );
11644 // ---------------------------------
11645 // 2. Add missing boundary elements
11646 // ---------------------------------
11647 if ( targetMesh != myMesh )
11648 // instead of making a map of nodes in this mesh and targetMesh,
11649 // we create nodes with same IDs.
11650 for ( int i = 0; i < missingBndElems.size(); ++i )
11652 TConnectivity& srcNodes = missingBndElems[i];
11653 TConnectivity nodes( srcNodes.size() );
11654 for ( inode = 0; inode < nodes.size(); ++inode )
11655 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11656 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11658 /*noMedium=*/false))
11660 tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11664 for ( int i = 0; i < missingBndElems.size(); ++i )
11666 TConnectivity& nodes = missingBndElems[i];
11667 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11669 /*noMedium=*/false))
11671 SMDS_MeshElement* elem =
11672 tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11675 // try to set a new element to a shape
11676 if ( myMesh->HasShapeToMesh() )
11679 set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11680 const int nbN = nodes.size() / (iQuad+1 );
11681 for ( inode = 0; inode < nbN && ok; ++inode )
11683 pair<int, TopAbs_ShapeEnum> i_stype =
11684 helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11685 if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11686 mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11688 if ( ok && mediumShapes.size() > 1 )
11690 set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11691 pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11692 for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11694 if (( ok = ( stype_i->first != stype_i_0.first )))
11695 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11696 aMesh->IndexToShape( stype_i_0.second ));
11699 if ( ok && mediumShapes.begin()->first == missShapeType )
11700 aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11704 // ----------------------------------
11705 // 3. Copy present boundary elements
11706 // ----------------------------------
11707 if ( toCopyExistingBoundary )
11708 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11710 const SMDS_MeshElement* e = presentBndElems[i];
11711 TConnectivity nodes( e->NbNodes() );
11712 for ( inode = 0; inode < nodes.size(); ++inode )
11713 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11714 presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11716 else // store present elements to add them to a group
11717 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11719 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11722 } // loop on given elements
11724 // ---------------------------------------------
11725 // 4. Fill group with boundary elements
11726 // ---------------------------------------------
11729 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11730 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11731 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11733 tgtEditor.myLastCreatedElems.Clear();
11734 tgtEditor2.myLastCreatedElems.Clear();
11736 // -----------------------
11737 // 5. Copy given elements
11738 // -----------------------
11739 if ( toCopyElements && targetMesh != myMesh )
11741 if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
11742 else eIt = elemSetIterator( elements );
11743 while (eIt->more())
11745 const SMDS_MeshElement* elem = eIt->next();
11746 TConnectivity nodes( elem->NbNodes() );
11747 for ( inode = 0; inode < nodes.size(); ++inode )
11748 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11749 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11751 tgtEditor.myLastCreatedElems.Clear();