-// SMESH SMESH : idl implementation based on 'SMESH' unit's classes
+// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
//
-// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
// This library is free software; you can redistribute it and/or
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
-// See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
-//
-//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
+
+// SMESH SMESH : idl implementation based on 'SMESH' unit's classes
// File : SMESH_MeshEditor.cxx
// Created : Mon Apr 12 16:10:22 2004
// Author : Edward AGAPOV (eap)
-
-
+//
+#define CHRONODEF
#include "SMESH_MeshEditor.hxx"
#include "SMDS_FaceOfNodes.hxx"
#include "SMDS_PolyhedralVolumeOfNodes.hxx"
#include "SMDS_FacePosition.hxx"
#include "SMDS_SpacePosition.hxx"
-#include "SMDS_QuadraticFaceOfNodes.hxx"
+//#include "SMDS_QuadraticFaceOfNodes.hxx"
+#include "SMDS_MeshGroup.hxx"
+#include "SMDS_LinearEdge.hxx"
+#include "SMDS_Downward.hxx"
+#include "SMDS_SetIterator.hxx"
#include "SMESHDS_Group.hxx"
#include "SMESHDS_Mesh.hxx"
-#include "SMESH_subMesh.hxx"
+#include "SMESH_Algo.hxx"
#include "SMESH_ControlsDef.hxx"
+#include "SMESH_Group.hxx"
#include "SMESH_MesherHelper.hxx"
+#include "SMESH_OctreeNode.hxx"
+#include "SMESH_subMesh.hxx"
#include "utilities.h"
-#include <TopTools_ListIteratorOfListOfShape.hxx>
-#include <TopTools_ListOfShape.hxx>
-#include <math.h>
-#include <gp_Dir.hxx>
-#include <gp_Vec.hxx>
-#include <gp_Ax1.hxx>
-#include <gp_Trsf.hxx>
-#include <gp_Lin.hxx>
-#include <gp_XYZ.hxx>
-#include <gp_XY.hxx>
-#include <gp.hxx>
-#include <gp_Pln.hxx>
+#include <BRepAdaptor_Surface.hxx>
+#include <BRepClass3d_SolidClassifier.hxx>
#include <BRep_Tool.hxx>
-#include <Geom_Curve.hxx>
-#include <Geom_Surface.hxx>
-#include <Geom2d_Curve.hxx>
+#include <ElCLib.hxx>
#include <Extrema_GenExtPS.hxx>
+#include <Extrema_POnCurv.hxx>
#include <Extrema_POnSurf.hxx>
+#include <GC_MakeSegment.hxx>
+#include <Geom2d_Curve.hxx>
+#include <GeomAPI_ExtremaCurveCurve.hxx>
#include <GeomAdaptor_Surface.hxx>
-#include <ElCLib.hxx>
+#include <Geom_Curve.hxx>
+#include <Geom_Line.hxx>
+#include <Geom_Surface.hxx>
+#include <IntAna_IntConicQuad.hxx>
+#include <IntAna_Quadric.hxx>
+#include <Precision.hxx>
#include <TColStd_ListOfInteger.hxx>
+#include <TopAbs_State.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_ListOfShape.hxx>
+#include <TopTools_SequenceOfShape.hxx>
+#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
+#include <gp.hxx>
+#include <gp_Ax1.hxx>
+#include <gp_Dir.hxx>
+#include <gp_Lin.hxx>
+#include <gp_Pln.hxx>
+#include <gp_Trsf.hxx>
+#include <gp_Vec.hxx>
+#include <gp_XY.hxx>
+#include <gp_XYZ.hxx>
+
+#include <math.h>
#include <map>
+#include <set>
+#include <numeric>
+#include <limits>
+
+#define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
using namespace std;
using namespace SMESH::Controls;
-typedef map<const SMDS_MeshNode*, const SMDS_MeshNode*> TNodeNodeMap;
typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
-typedef map<const SMDS_MeshNode*, list<const SMDS_MeshNode*> > TNodeOfNodeListMap;
-typedef TNodeOfNodeListMap::iterator TNodeOfNodeListMapItr;
-//typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> > TNodeOfNodeVecMap;
-//typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr;
-typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeListMapItr> > TElemOfVecOfNnlmiMap;
-//typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> > TElemOfVecOfMapNodesMap;
-typedef pair<const SMDS_MeshNode*, const SMDS_MeshNode*> NLink;
+typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
//=======================================================================
//function : SMESH_MeshEditor
//purpose :
//=======================================================================
-SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ):
-myMesh( theMesh )
+SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
+ :myMesh( theMesh ) // theMesh may be NULL
+{
+}
+
+//=======================================================================
+/*!
+ * \brief Add element
+ */
+//=======================================================================
+
+SMDS_MeshElement*
+SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
+ const SMDSAbs_ElementType type,
+ const bool isPoly,
+ const int ID)
+{
+ //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
+ SMDS_MeshElement* e = 0;
+ int nbnode = node.size();
+ SMESHDS_Mesh* mesh = GetMeshDS();
+ switch ( type ) {
+ case SMDSAbs_Face:
+ if ( !isPoly ) {
+ if (nbnode == 3) {
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2] );
+ }
+ else if (nbnode == 4) {
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
+ }
+ else if (nbnode == 6) {
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2], node[3],
+ node[4], node[5] );
+ }
+ else if (nbnode == 8) {
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7] );
+ }
+ } else {
+ if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
+ else e = mesh->AddPolygonalFace (node );
+ }
+ break;
+
+ case SMDSAbs_Volume:
+ if ( !isPoly ) {
+ if (nbnode == 4) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
+ }
+ else if (nbnode == 5) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4] );
+ }
+ else if (nbnode == 6) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5] );
+ }
+ else if (nbnode == 8) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7] );
+ }
+ else if (nbnode == 10) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9] );
+ }
+ else if (nbnode == 13) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10],node[11],
+ node[12],ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10],node[11],
+ node[12] );
+ }
+ else if (nbnode == 15) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10],node[11],
+ node[12],node[13],node[14],ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10],node[11],
+ node[12],node[13],node[14] );
+ }
+ else if (nbnode == 20) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10],node[11],
+ node[12],node[13],node[14],node[15],
+ node[16],node[17],node[18],node[19],ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10],node[11],
+ node[12],node[13],node[14],node[15],
+ node[16],node[17],node[18],node[19] );
+ }
+ }
+ break;
+
+ case SMDSAbs_Edge:
+ if ( nbnode == 2 ) {
+ if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
+ else e = mesh->AddEdge (node[0], node[1] );
+ }
+ else if ( nbnode == 3 ) {
+ if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
+ else e = mesh->AddEdge (node[0], node[1], node[2] );
+ }
+ break;
+
+ case SMDSAbs_0DElement:
+ if ( nbnode == 1 ) {
+ if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
+ else e = mesh->Add0DElement (node[0] );
+ }
+ break;
+
+ case SMDSAbs_Node:
+ if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
+ else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
+ break;
+
+ default:;
+ }
+ if ( e ) myLastCreatedElems.Append( e );
+ return e;
+}
+
+//=======================================================================
+/*!
+ * \brief Add element
+ */
+//=======================================================================
+
+SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
+ const SMDSAbs_ElementType type,
+ const bool isPoly,
+ const int ID)
{
+ vector<const SMDS_MeshNode*> nodes;
+ nodes.reserve( nodeIDs.size() );
+ vector<int>::const_iterator id = nodeIDs.begin();
+ while ( id != nodeIDs.end() ) {
+ if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
+ nodes.push_back( node );
+ else
+ return 0;
+ }
+ return AddElement( nodes, type, isPoly, ID );
}
//=======================================================================
// Modify a compute state of sub-meshes which become empty
//=======================================================================
-bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
- const bool isNodes )
+int SMESH_MeshEditor::Remove (const list< int >& theIDs,
+ const bool isNodes )
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
SMESHDS_Mesh* aMesh = GetMeshDS();
set< SMESH_subMesh *> smmap;
+ int removed = 0;
list<int>::const_iterator it = theIDs.begin();
for ( ; it != theIDs.end(); it++ ) {
const SMDS_MeshElement * elem;
if ( !elem )
continue;
- // Find sub-meshes to notify about modification
- SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
- while ( nodeIt->more() ) {
- const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
- const SMDS_PositionPtr& aPosition = node->GetPosition();
- if ( aPosition.get() ) {
- if ( int aShapeID = aPosition->GetShapeId() ) {
+ // Notify VERTEX sub-meshes about modification
+ if ( isNodes ) {
+ const SMDS_MeshNode* node = cast2Node( elem );
+ if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
+ if ( int aShapeID = node->getshapeId() )
if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
smmap.insert( sm );
- }
- }
}
+ // Find sub-meshes to notify about modification
+ // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+ // while ( nodeIt->more() ) {
+ // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+ // const SMDS_PositionPtr& aPosition = node->GetPosition();
+ // if ( aPosition.get() ) {
+ // if ( int aShapeID = aPosition->GetShapeId() ) {
+ // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
+ // smmap.insert( sm );
+ // }
+ // }
+ // }
// Do remove
if ( isNodes )
aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
else
aMesh->RemoveElement( elem );
+ removed++;
}
// Notify sub-meshes about modification
(*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
}
- // Check if the whole mesh becomes empty
- if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
- sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+ // // Check if the whole mesh becomes empty
+ // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
+ // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
- return true;
+ return removed;
}
//=======================================================================
if ( aMesh->ShapeToMesh().IsNull() )
return 0;
- if ( theElem->GetType() == SMDSAbs_Node ) {
- const SMDS_PositionPtr& aPosition =
- static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
- if ( aPosition.get() )
- return aPosition->GetShapeId();
- else
- return 0;
- }
+ if ( theElem->GetType() == SMDSAbs_Node )
+ {
+ int aShapeID = theElem->getshapeId();
+ if (aShapeID <= 0)
+ return 0;
+ else
+ return aShapeID;
+ }
TopoDS_Shape aShape; // the shape a node is on
SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
while ( nodeIt->more() ) {
const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
- const SMDS_PositionPtr& aPosition = node->GetPosition();
- if ( aPosition.get() ) {
- int aShapeID = aPosition->GetShapeId();
+ int aShapeID = node->getshapeId();
+ if (aShapeID > 0) {
SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
if ( sm ) {
if ( sm->Contains( theElem ))
//=======================================================================
//function : IsMedium
-//purpose :
+//purpose :
//=======================================================================
bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
const SMDSAbs_ElementType typeToCheck)
{
bool isMedium = false;
- SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
- while (it->more()) {
+ SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
+ while (it->more() && !isMedium ) {
const SMDS_MeshElement* elem = it->next();
isMedium = elem->IsMediumNode(node);
- if ( typeToCheck == SMDSAbs_All || elem->GetType() == typeToCheck )
- break;
}
return isMedium;
}
ShiftNodesQuadTria(N2);
}
// now we receive following N1 and N2 (using numeration as above image)
- // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
+ // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
// i.e. first nodes from both arrays determ new diagonal
return true;
}
bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
const SMDS_MeshElement * theTria2 )
{
+ MESSAGE("InverseDiag");
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
if (!theTria1 || !theTria2)
return false;
- const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
- const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
- if (F1 && F2) {
+ const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
+ if (!F1) return false;
+ const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
+ if (!F2) return false;
+ if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
+ (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
// 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
// | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
while ( it->more() ) {
aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
-
+
if ( i > 2 ) // theTria2
// find same node of theTria1
for ( int j = 0; j < 3; j++ )
if ( i == 6 && it->more() )
return false; // theTria2 is not a triangle
}
-
+
// find indices of 1,2 and of A,B in theTria1
int iA = 0, iB = 0, i1 = 0, i2 = 0;
for ( i = 0; i < 6; i++ ) {
- if ( sameInd [ i ] == 0 )
+ if ( sameInd [ i ] == 0 ) {
if ( i < 3 ) i1 = i;
else i2 = i;
- else if (i < 3)
+ }
+ else if (i < 3) {
if ( iA ) iB = i;
else iA = i;
+ }
}
// nodes 1 and 2 should not be the same
if ( aNodes[ i1 ] == aNodes[ i2 ] )
// theTria2: B->1
aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
- //MESSAGE( theTria1 << theTria2 );
-
GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
-
- //MESSAGE( theTria1 << theTria2 );
return true;
-
+
} // end if(F1 && F2)
// check case of quadratic faces
- const SMDS_QuadraticFaceOfNodes* QF1 =
- dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
- if(!QF1) return false;
- const SMDS_QuadraticFaceOfNodes* QF2 =
- dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
- if(!QF2) return false;
+ if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
+ return false;
+ if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
+ return false;
// 5
// 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
// | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
- // | / |
+ // | / |
// 7 + + + 6
// | /9 |
// |/ |
- // 4 +--+--+ 3
+ // 4 +--+--+ 3
// 8
-
+
const SMDS_MeshNode* N1 [6];
const SMDS_MeshNode* N2 [6];
if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
return false;
// now we receive following N1 and N2 (using numeration as above image)
- // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
+ // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
// i.e. first nodes from both arrays determ new diagonal
const SMDS_MeshNode* N1new [6];
theTria1 = theTria2 = 0;
set< const SMDS_MeshElement* > emap;
- SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator();
+ SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
while (it->more()) {
const SMDS_MeshElement* elem = it->next();
- if ( elem->GetType() == SMDSAbs_Face && elem->NbNodes() == 3 )
+ if ( elem->NbNodes() == 3 )
emap.insert( elem );
}
- it = theNode2->GetInverseElementIterator();
+ it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
while (it->more()) {
const SMDS_MeshElement* elem = it->next();
- if ( elem->GetType() == SMDSAbs_Face &&
- emap.find( elem ) != emap.end() )
+ if ( emap.find( elem ) != emap.end() ) {
if ( theTria1 ) {
// theTria1 must be element with minimum ID
if( theTria1->GetID() < elem->GetID() ) {
else {
theTria1 = elem;
}
+ }
}
return ( theTria1 && theTria2 );
}
if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
return false;
- const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
- //if (!F1) return false;
- const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
- //if (!F2) return false;
- if (F1 && F2) {
+ const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
+ if (!F1) return false;
+ const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
+ if (!F2) return false;
+ if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
+ (tr2->GetEntityType() == SMDSEntity_Triangle)) {
// 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
// | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
else if ( aNodes2[ i ] != theNode1 )
i2 = i; // node 2
}
-
+
// nodes 1 and 2 should not be the same
if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
return false;
// tr2: B->1
aNodes2[ iB2 ] = aNodes1[ i1 ];
- //MESSAGE( tr1 << tr2 );
-
GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
- //MESSAGE( tr1 << tr2 );
-
return true;
}
// check case of quadratic faces
- const SMDS_QuadraticFaceOfNodes* QF1 =
- dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
- if(!QF1) return false;
- const SMDS_QuadraticFaceOfNodes* QF2 =
- dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
- if(!QF2) return false;
return InverseDiag(tr1,tr2);
}
const SMDS_MeshNode* n4 = 0;
SMDS_ElemIteratorPtr it = tr2->nodesIterator();
int i=0;
- //while ( !n4 && it->more() ) {
while ( !n4 && i<3 ) {
- const SMDS_MeshNode * n = static_cast<const SMDS_MeshNode*>( it->next() );
+ const SMDS_MeshNode * n = cast2Node( it->next() );
i++;
bool isDiag = ( n == theNode1 || n == theNode2 );
if ( !isDiag )
int iNode = 0, iFirstDiag = -1;
it = tr1->nodesIterator();
i=0;
- //while ( it->more() ) {
while ( i<3 ) {
- const SMDS_MeshNode * n = static_cast<const SMDS_MeshNode*>( it->next() );
+ const SMDS_MeshNode * n = cast2Node( it->next() );
i++;
bool isDiag = ( n == theNode1 || n == theNode2 );
if ( isDiag ) {
if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
return false;
- const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
- //if (!F1) return false;
- const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
- //if (!F2) return false;
- if (F1 && F2) {
+ const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
+ if (!F1) return false;
+ const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
+ if (!F2) return false;
+ SMESHDS_Mesh * aMesh = GetMeshDS();
+
+ if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
+ (tr2->GetEntityType() == SMDSEntity_Triangle)) {
const SMDS_MeshNode* aNodes [ 4 ];
if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
return false;
- //MESSAGE( endl << tr1 << tr2 );
-
- GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
- myLastCreatedElems.Append(tr1);
- GetMeshDS()->RemoveElement( tr2 );
-
- //MESSAGE( endl << tr1 );
+ const SMDS_MeshElement* newElem = 0;
+ newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
+ myLastCreatedElems.Append(newElem);
+ AddToSameGroups( newElem, tr1, aMesh );
+ int aShapeId = tr1->getshapeId();
+ if ( aShapeId )
+ {
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ aMesh->RemoveElement( tr1 );
+ aMesh->RemoveElement( tr2 );
return true;
}
// check case of quadratic faces
- const SMDS_QuadraticFaceOfNodes* QF1 =
- dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
- if(!QF1) return false;
- const SMDS_QuadraticFaceOfNodes* QF2 =
- dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
- if(!QF2) return false;
+ if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
+ return false;
+ if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
+ return false;
// 5
// 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
// | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
- // | / |
+ // | / |
// 7 + + + 6
// | /9 |
// |/ |
- // 4 +--+--+ 3
+ // 4 +--+--+ 3
// 8
-
+
const SMDS_MeshNode* N1 [6];
const SMDS_MeshNode* N2 [6];
if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
return false;
// now we receive following N1 and N2 (using numeration as above image)
- // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
+ // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
// i.e. first nodes from both arrays determ new diagonal
const SMDS_MeshNode* aNodes[8];
aNodes[6] = N2[3];
aNodes[7] = N1[5];
- GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
- myLastCreatedElems.Append(tr1);
- GetMeshDS()->RemoveElement( tr2 );
+ const SMDS_MeshElement* newElem = 0;
+ newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+ aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+ myLastCreatedElems.Append(newElem);
+ AddToSameGroups( newElem, tr1, aMesh );
+ int aShapeId = tr1->getshapeId();
+ if ( aShapeId )
+ {
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ aMesh->RemoveElement( tr1 );
+ aMesh->RemoveElement( tr2 );
// remove middle node (9)
GetMeshDS()->RemoveNode( N1[4] );
bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
{
+ MESSAGE("Reorient");
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
}
case SMDSAbs_Volume: {
if (theElem->IsPoly()) {
- const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
- static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
+ // TODO reorient vtk polyhedron
+ MESSAGE("reorient vtk polyhedron ?");
+ const SMDS_VtkVolume* aPolyedre =
+ dynamic_cast<const SMDS_VtkVolume*>( theElem );
if (!aPolyedre) {
MESSAGE("Warning: bad volumic element");
return false;
for (int iface = 1; iface <= nbFaces; iface++) {
int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
quantities[iface - 1] = nbFaceNodes;
-
+
for (inode = nbFaceNodes; inode >= 1; inode--) {
const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
poly_nodes.push_back(curNode);
}
}
-
+
return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
}
if ( !vTool.Set( theElem ))
return false;
vTool.Inverse();
+ MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
}
}
// theCrit is used to select a diagonal to cut
//=======================================================================
-bool SMESH_MeshEditor::QuadToTri (map<int,const SMDS_MeshElement*> & theElems,
+bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
SMESH::Controls::NumericalFunctorPtr theCrit)
{
myLastCreatedElems.Clear();
Handle(Geom_Surface) surface;
SMESH_MesherHelper helper( *GetMesh() );
- map<int, const SMDS_MeshElement * >::iterator itElem;
+ TIDSortedElemSet::iterator itElem;
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- const SMDS_MeshElement* elem = (*itElem).second;
+ const SMDS_MeshElement* elem = *itElem;
if ( !elem || elem->GetType() != SMDSAbs_Face )
continue;
if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
int aShapeId = FindShape( elem );
- const SMDS_MeshElement* newElem = 0;
+ const SMDS_MeshElement* newElem1 = 0;
+ const SMDS_MeshElement* newElem2 = 0;
if( !elem->IsQuadratic() ) {
// split liner quadrangle
-
if ( aBadRate1 <= aBadRate2 ) {
// tr1 + tr2 is better
- aMesh->ChangeElementNodes( elem, aNodes, 3 );
- newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+ newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+ newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
}
else {
// tr3 + tr4 is better
- aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
- newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+ newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+ newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
}
}
else {
- // split qudratic quadrangle
+ // split quadratic quadrangle
// get surface elem is on
if ( aShapeId != helper.GetSubShapeID() ) {
aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
{
inFaceNode = aNodes[ i-1 ];
- }
+ }
}
// find middle point for (0,1,2,3)
// and create a node in this point;
N[3] = aNodes[4];
N[4] = aNodes[5];
N[5] = newN;
- newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
- aNodes[6], aNodes[7], newN );
+ newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
+ aNodes[6], aNodes[7], newN );
+ newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
+ newN, aNodes[4], aNodes[5] );
}
else {
N[0] = aNodes[1];
N[3] = aNodes[5];
N[4] = aNodes[6];
N[5] = newN;
- newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
- aNodes[7], aNodes[4], newN );
+ newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
+ aNodes[7], aNodes[4], newN );
+ newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
+ newN, aNodes[5], aNodes[6] );
}
- aMesh->ChangeElementNodes( elem, N, 6 );
-
- } // qudratic case
+ } // quadratic case
// care of a new element
- myLastCreatedElems.Append(newElem);
- AddToSameGroups( newElem, elem, aMesh );
+ myLastCreatedElems.Append(newElem1);
+ myLastCreatedElems.Append(newElem2);
+ AddToSameGroups( newElem1, elem, aMesh );
+ AddToSameGroups( newElem2, elem, aMesh );
// put a new triangle on the same shape
if ( aShapeId )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ {
+ aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+ aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+ }
+ aMesh->RemoveElement( elem );
}
return true;
}
//function : BestSplit
//purpose : Find better diagonal for cutting.
//=======================================================================
+
int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
SMESH::Controls::NumericalFunctorPtr theCrit)
{
return -1;
}
-//=======================================================================
-//function : AddToSameGroups
-//purpose : add elemToAdd to the groups the elemInGroups belongs to
-//=======================================================================
-
-void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
- const SMDS_MeshElement* elemInGroups,
- SMESHDS_Mesh * aMesh)
+namespace
{
- const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
- set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
- for ( ; grIt != groups.end(); grIt++ ) {
- SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
- if ( group && group->SMDSGroup().Contains( elemInGroups ))
- group->SMDSGroup().Add( elemToAdd );
- }
-}
+ // Methods of splitting volumes into tetra
+ const int theHexTo5_1[5*4+1] =
+ {
+ 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
+ };
+ const int theHexTo5_2[5*4+1] =
+ {
+ 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
+ };
+ const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
-//=======================================================================
-//function : RemoveElemFromGroups
-//purpose : Remove removeelem to the groups the elemInGroups belongs to
-//=======================================================================
-void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
- SMESHDS_Mesh * aMesh)
-{
- const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
- if (!groups.empty())
- {
- set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
- for (; GrIt != groups.end(); GrIt++)
+ const int theHexTo6_1[6*4+1] =
{
- SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
- if (!grp || grp->IsEmpty()) continue;
- grp->SMDSGroup().Remove(removeelem);
- }
- }
-}
+ 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
+ };
+ const int theHexTo6_2[6*4+1] =
+ {
+ 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
+ };
+ const int theHexTo6_3[6*4+1] =
+ {
+ 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
+ };
+ const int theHexTo6_4[6*4+1] =
+ {
+ 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
+ };
+ const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
+ const int thePyraTo2_1[2*4+1] =
+ {
+ 0, 1, 2, 4, 0, 2, 3, 4, -1
+ };
+ const int thePyraTo2_2[2*4+1] =
+ {
+ 1, 2, 3, 4, 1, 3, 0, 4, -1
+ };
+ const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
-//=======================================================================
-//function : QuadToTri
-//purpose : Cut quadrangles into triangles.
-// theCrit is used to select a diagonal to cut
-//=======================================================================
+ const int thePentaTo3_1[3*4+1] =
+ {
+ 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
+ };
+ const int thePentaTo3_2[3*4+1] =
+ {
+ 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
+ };
+ const int thePentaTo3_3[3*4+1] =
+ {
+ 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
+ };
+ const int thePentaTo3_4[3*4+1] =
+ {
+ 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
+ };
+ const int thePentaTo3_5[3*4+1] =
+ {
+ 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
+ };
+ const int thePentaTo3_6[3*4+1] =
+ {
+ 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
+ };
+ const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
+ thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
-bool SMESH_MeshEditor::QuadToTri (std::map<int,const SMDS_MeshElement*> & theElems,
- const bool the13Diag)
-{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ struct TTriangleFacet //!< stores indices of three nodes of tetra facet
+ {
+ int _n1, _n2, _n3;
+ TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
+ bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
+ bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
+ };
+ struct TSplitMethod
+ {
+ int _nbTetra;
+ const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
+ bool _baryNode; //!< additional node is to be created at cell barycenter
+ bool _ownConn; //!< to delete _connectivity in destructor
+ map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
+
+ TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
+ : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
+ ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
+ bool hasFacet( const TTriangleFacet& facet ) const
+ {
+ const int* tetConn = _connectivity;
+ for ( ; tetConn[0] >= 0; tetConn += 4 )
+ if (( facet.contains( tetConn[0] ) +
+ facet.contains( tetConn[1] ) +
+ facet.contains( tetConn[2] ) +
+ facet.contains( tetConn[3] )) == 3 )
+ return true;
+ return false;
+ }
+ };
- MESSAGE( "::QuadToTri()" );
+ //=======================================================================
+ /*!
+ * \brief return TSplitMethod for the given element
+ */
+ //=======================================================================
- SMESHDS_Mesh * aMesh = GetMeshDS();
+ TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
+ {
+ const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
- Handle(Geom_Surface) surface;
- SMESH_MesherHelper helper( *GetMesh() );
+ // at HEXA_TO_24 method, each face of volume is split into triangles each based on
+ // an edge and a face barycenter; tertaherdons are based on triangles and
+ // a volume barycenter
+ const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
- map<int, const SMDS_MeshElement * >::iterator itElem;
- for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- const SMDS_MeshElement* elem = (*itElem).second;
- if ( !elem || elem->GetType() != SMDSAbs_Face )
- continue;
- bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
- if(!isquad) continue;
+ // Find out how adjacent volumes are split
- if(elem->NbNodes()==4) {
- // retrieve element nodes
- const SMDS_MeshNode* aNodes [4];
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- int i = 0;
- while ( itN->more() )
- aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+ vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
+ int hasAdjacentSplits = 0, maxTetConnSize = 0;
+ for ( int iF = 0; iF < vol.NbFaces(); ++iF )
+ {
+ int nbNodes = vol.NbFaceNodes( iF ) / iQ;
+ maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
+ if ( nbNodes < 4 ) continue;
- int aShapeId = FindShape( elem );
- const SMDS_MeshElement* newElem = 0;
- if ( the13Diag ) {
- aMesh->ChangeElementNodes( elem, aNodes, 3 );
- newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+ list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
+ const int* nInd = vol.GetFaceNodesIndices( iF );
+ if ( nbNodes == 4 )
+ {
+ TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
+ TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
+ if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
+ else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
}
- else {
- aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
- newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+ else
+ {
+ int iCom = 0; // common node of triangle faces to split into
+ for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
+ {
+ TTriangleFacet t012( nInd[ iQ * ( iCom )],
+ nInd[ iQ * ( (iCom+1)%nbNodes )],
+ nInd[ iQ * ( (iCom+2)%nbNodes )]);
+ TTriangleFacet t023( nInd[ iQ * ( iCom )],
+ nInd[ iQ * ( (iCom+2)%nbNodes )],
+ nInd[ iQ * ( (iCom+3)%nbNodes )]);
+ if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
+ {
+ triaSplits.push_back( t012 );
+ triaSplits.push_back( t023 );
+ break;
+ }
+ }
}
- myLastCreatedElems.Append(newElem);
- // put a new triangle on the same shape and add to the same groups
- if ( aShapeId )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- AddToSameGroups( newElem, elem, aMesh );
+ if ( !triaSplits.empty() )
+ hasAdjacentSplits = true;
}
- // Quadratic quadrangle
-
- if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
+ // Among variants of split method select one compliant with adjacent volumes
- // get surface elem is on
- int aShapeId = FindShape( elem );
- if ( aShapeId != helper.GetSubShapeID() ) {
- surface.Nullify();
- TopoDS_Shape shape;
- if ( aShapeId > 0 )
- shape = aMesh->IndexToShape( aShapeId );
- if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
- TopoDS_Face face = TopoDS::Face( shape );
- surface = BRep_Tool::Surface( face );
- if ( !surface.IsNull() )
- helper.SetSubShape( shape );
+ TSplitMethod method;
+ if ( !vol.Element()->IsPoly() && !is24TetMode )
+ {
+ int nbVariants = 2, nbTet = 0;
+ const int** connVariants = 0;
+ switch ( vol.Element()->GetEntityType() )
+ {
+ case SMDSEntity_Hexa:
+ case SMDSEntity_Quad_Hexa:
+ if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
+ connVariants = theHexTo5, nbTet = 5;
+ else
+ connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
+ break;
+ case SMDSEntity_Pyramid:
+ case SMDSEntity_Quad_Pyramid:
+ connVariants = thePyraTo2; nbTet = 2;
+ break;
+ case SMDSEntity_Penta:
+ case SMDSEntity_Quad_Penta:
+ connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
+ break;
+ default:
+ nbVariants = 0;
+ }
+ for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
+ {
+ // check method compliancy with adjacent tetras,
+ // all found splits must be among facets of tetras described by this method
+ method = TSplitMethod( nbTet, connVariants[variant] );
+ if ( hasAdjacentSplits && method._nbTetra > 0 )
+ {
+ bool facetCreated = true;
+ for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
+ {
+ list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
+ for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
+ facetCreated = method.hasFacet( *facet );
+ }
+ if ( !facetCreated )
+ method = TSplitMethod(0); // incompatible method
+ }
+ }
+ }
+ if ( method._nbTetra < 1 )
+ {
+ // No standard method is applicable, use a generic solution:
+ // each facet of a volume is split into triangles and
+ // each of triangles and a volume barycenter form a tetrahedron.
+
+ int* connectivity = new int[ maxTetConnSize + 1 ];
+ method._connectivity = connectivity;
+ method._ownConn = true;
+ method._baryNode = true;
+
+ int connSize = 0;
+ int baryCenInd = vol.NbNodes();
+ for ( int iF = 0; iF < vol.NbFaces(); ++iF )
+ {
+ const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
+ const int* nInd = vol.GetFaceNodesIndices( iF );
+ // find common node of triangle facets of tetra to create
+ int iCommon = 0; // index in linear numeration
+ const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
+ if ( !triaSplits.empty() )
+ {
+ // by found facets
+ const TTriangleFacet* facet = &triaSplits.front();
+ for ( ; iCommon < nbNodes-1 ; ++iCommon )
+ if ( facet->contains( nInd[ iQ * iCommon ]) &&
+ facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
+ break;
+ }
+ else if ( nbNodes > 3 && !is24TetMode )
+ {
+ // find the best method of splitting into triangles by aspect ratio
+ SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
+ map< double, int > badness2iCommon;
+ const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
+ int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
+ for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
+ for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
+ {
+ SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
+ nodes[ iQ*((iLast-1)%nbNodes)],
+ nodes[ iQ*((iLast )%nbNodes)]);
+ double badness = getBadRate( &tria, aspectRatio );
+ badness2iCommon.insert( make_pair( badness, iCommon ));
+ }
+ // use iCommon with lowest badness
+ iCommon = badness2iCommon.begin()->second;
+ }
+ if ( iCommon >= nbNodes )
+ iCommon = 0; // something wrong
+
+ // fill connectivity of tetrahedra based on a current face
+ int nbTet = nbNodes - 2;
+ if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
+ {
+ method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
+ int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
+ nbTet = nbNodes;
+ for ( int i = 0; i < nbTet; ++i )
+ {
+ int i1 = i, i2 = (i+1) % nbNodes;
+ if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
+ connectivity[ connSize++ ] = nInd[ iQ * i1 ];
+ connectivity[ connSize++ ] = nInd[ iQ * i2 ];
+ connectivity[ connSize++ ] = faceBaryCenInd;
+ connectivity[ connSize++ ] = baryCenInd;
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < nbTet; ++i )
+ {
+ int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
+ if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
+ connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
+ connectivity[ connSize++ ] = nInd[ iQ * i1 ];
+ connectivity[ connSize++ ] = nInd[ iQ * i2 ];
+ connectivity[ connSize++ ] = baryCenInd;
+ }
+ }
+ method._nbTetra += nbTet;
+ }
+ connectivity[ connSize++ ] = -1;
+ }
+ return method;
+ }
+ //================================================================================
+ /*!
+ * \brief Check if there is a tetraherdon adjacent to the given element via this facet
+ */
+ //================================================================================
+
+ bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
+ {
+ // find the tetrahedron including the three nodes of facet
+ const SMDS_MeshNode* n1 = elem->GetNode(_n1);
+ const SMDS_MeshNode* n2 = elem->GetNode(_n2);
+ const SMDS_MeshNode* n3 = elem->GetNode(_n3);
+ SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
+ while ( volIt1->more() )
+ {
+ const SMDS_MeshElement* v = volIt1->next();
+ if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
+ continue;
+ SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
+ while ( volIt2->more() )
+ if ( v != volIt2->next() )
+ continue;
+ SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
+ while ( volIt3->more() )
+ if ( v == volIt3->next() )
+ return true;
+ }
+ return false;
+ }
+
+ //=======================================================================
+ /*!
+ * \brief A key of a face of volume
+ */
+ //=======================================================================
+
+ struct TVolumeFaceKey: pair< int, pair< int, int> >
+ {
+ TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
+ {
+ TIDSortedNodeSet sortedNodes;
+ const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
+ int nbNodes = vol.NbFaceNodes( iF );
+ const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
+ for ( int i = 0; i < nbNodes; i += iQ )
+ sortedNodes.insert( fNodes[i] );
+ TIDSortedNodeSet::iterator n = sortedNodes.begin();
+ first = (*(n++))->GetID();
+ second.first = (*(n++))->GetID();
+ second.second = (*(n++))->GetID();
+ }
+ };
+} // namespace
+
+//=======================================================================
+//function : SplitVolumesIntoTetra
+//purpose : Split volumic elements into tetrahedra.
+//=======================================================================
+
+void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
+ const int theMethodFlags)
+{
+ // std-like iterator on coordinates of nodes of mesh element
+ typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
+ NXyzIterator xyzEnd;
+
+ SMDS_VolumeTool volTool;
+ SMESH_MesherHelper helper( *GetMesh());
+
+ SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
+ SMESHDS_SubMesh* fSubMesh = subMesh;
+
+ SMESH_SequenceOfElemPtr newNodes, newElems;
+
+ // map face of volume to it's baricenrtic node
+ map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
+ double bc[3];
+
+ TIDSortedElemSet::const_iterator elem = theElems.begin();
+ for ( ; elem != theElems.end(); ++elem )
+ {
+ SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
+ if ( geomType <= SMDSEntity_Quad_Tetra )
+ continue; // tetra or face or ...
+
+ if ( !volTool.Set( *elem )) continue; // not volume? strange...
+
+ TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
+ if ( splitMethod._nbTetra < 1 ) continue;
+
+ // find submesh to add new tetras to
+ if ( !subMesh || !subMesh->Contains( *elem ))
+ {
+ int shapeID = FindShape( *elem );
+ helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
+ subMesh = GetMeshDS()->MeshElements( shapeID );
+ }
+ int iQ;
+ if ( (*elem)->IsQuadratic() )
+ {
+ iQ = 2;
+ // add quadratic links to the helper
+ for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
+ {
+ const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
+ for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
+ helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
+ }
+ helper.SetIsQuadratic( true );
+ }
+ else
+ {
+ iQ = 1;
+ helper.SetIsQuadratic( false );
+ }
+ vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
+ if ( splitMethod._baryNode )
+ {
+ // make a node at barycenter
+ volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
+ SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
+ nodes.push_back( gcNode );
+ newNodes.Append( gcNode );
+ }
+ if ( !splitMethod._faceBaryNode.empty() )
+ {
+ // make or find baricentric nodes of faces
+ map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
+ for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
+ {
+ map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
+ volFace2BaryNode.insert
+ ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
+ if ( !f_n->second )
+ {
+ volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
+ newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
+ }
+ nodes.push_back( iF_n->second = f_n->second );
+ }
+ }
+
+ // make tetras
+ helper.SetElementsOnShape( true );
+ vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
+ const int* tetConn = splitMethod._connectivity;
+ for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
+ newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
+ nodes[ tetConn[1] ],
+ nodes[ tetConn[2] ],
+ nodes[ tetConn[3] ]));
+
+ ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
+
+ // Split faces on sides of the split volume
+
+ const SMDS_MeshNode** volNodes = volTool.GetNodes();
+ for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
+ {
+ const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
+ if ( nbNodes < 4 ) continue;
+
+ // find an existing face
+ vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
+ volTool.GetFaceNodes( iF ) + nbNodes*iQ );
+ while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
+ {
+ // make triangles
+ helper.SetElementsOnShape( false );
+ vector< const SMDS_MeshElement* > triangles;
+
+ map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
+ if ( iF_n != splitMethod._faceBaryNode.end() )
+ {
+ for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
+ {
+ const SMDS_MeshNode* n1 = fNodes[iN];
+ const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
+ const SMDS_MeshNode *n3 = iF_n->second;
+ if ( !volTool.IsFaceExternal( iF ))
+ swap( n2, n3 );
+ triangles.push_back( helper.AddFace( n1,n2,n3 ));
+ }
+ }
+ else
+ {
+ // among possible triangles create ones discribed by split method
+ const int* nInd = volTool.GetFaceNodesIndices( iF );
+ int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
+ int iCom = 0; // common node of triangle faces to split into
+ list< TTriangleFacet > facets;
+ for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
+ {
+ TTriangleFacet t012( nInd[ iQ * ( iCom )],
+ nInd[ iQ * ( (iCom+1)%nbNodes )],
+ nInd[ iQ * ( (iCom+2)%nbNodes )]);
+ TTriangleFacet t023( nInd[ iQ * ( iCom )],
+ nInd[ iQ * ( (iCom+2)%nbNodes )],
+ nInd[ iQ * ( (iCom+3)%nbNodes )]);
+ if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
+ {
+ facets.push_back( t012 );
+ facets.push_back( t023 );
+ for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
+ facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
+ nInd[ iQ * ((iLast-1)%nbNodes )],
+ nInd[ iQ * ((iLast )%nbNodes )]));
+ break;
+ }
+ }
+ list< TTriangleFacet >::iterator facet = facets.begin();
+ for ( ; facet != facets.end(); ++facet )
+ {
+ if ( !volTool.IsFaceExternal( iF ))
+ swap( facet->_n2, facet->_n3 );
+ triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
+ volNodes[ facet->_n2 ],
+ volNodes[ facet->_n3 ]));
+ }
+ }
+ // find submesh to add new triangles in
+ if ( !fSubMesh || !fSubMesh->Contains( face ))
+ {
+ int shapeID = FindShape( face );
+ fSubMesh = GetMeshDS()->MeshElements( shapeID );
+ }
+ for ( int i = 0; i < triangles.size(); ++i )
+ {
+ if ( !triangles[i] ) continue;
+ if ( fSubMesh )
+ fSubMesh->AddElement( triangles[i]);
+ newElems.Append( triangles[i] );
+ }
+ ReplaceElemInGroups( face, triangles, GetMeshDS() );
+ GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
+ }
+
+ } // loop on volume faces to split them into triangles
+
+ GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
+
+ } // loop on volumes to split
+
+ myLastCreatedNodes = newNodes;
+ myLastCreatedElems = newElems;
+}
+
+//=======================================================================
+//function : AddToSameGroups
+//purpose : add elemToAdd to the groups the elemInGroups belongs to
+//=======================================================================
+
+void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
+ const SMDS_MeshElement* elemInGroups,
+ SMESHDS_Mesh * aMesh)
+{
+ const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+ if (!groups.empty()) {
+ set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+ for ( ; grIt != groups.end(); grIt++ ) {
+ SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+ if ( group && group->Contains( elemInGroups ))
+ group->SMDSGroup().Add( elemToAdd );
+ }
+ }
+}
+
+
+//=======================================================================
+//function : RemoveElemFromGroups
+//purpose : Remove removeelem to the groups the elemInGroups belongs to
+//=======================================================================
+void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
+ SMESHDS_Mesh * aMesh)
+{
+ const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+ if (!groups.empty())
+ {
+ set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
+ for (; GrIt != groups.end(); GrIt++)
+ {
+ SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
+ if (!grp || grp->IsEmpty()) continue;
+ grp->SMDSGroup().Remove(removeelem);
+ }
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Replace elemToRm by elemToAdd in the all groups
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
+ const SMDS_MeshElement* elemToAdd,
+ SMESHDS_Mesh * aMesh)
+{
+ const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+ if (!groups.empty()) {
+ set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+ for ( ; grIt != groups.end(); grIt++ ) {
+ SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+ if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
+ group->SMDSGroup().Add( elemToAdd );
+ }
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Replace elemToRm by elemToAdd in the all groups
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
+ const vector<const SMDS_MeshElement*>& elemToAdd,
+ SMESHDS_Mesh * aMesh)
+{
+ const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+ if (!groups.empty())
+ {
+ set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+ for ( ; grIt != groups.end(); grIt++ ) {
+ SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+ if ( group && group->SMDSGroup().Remove( elemToRm ) )
+ for ( int i = 0; i < elemToAdd.size(); ++i )
+ group->SMDSGroup().Add( elemToAdd[ i ] );
+ }
+ }
+}
+
+//=======================================================================
+//function : QuadToTri
+//purpose : Cut quadrangles into triangles.
+// theCrit is used to select a diagonal to cut
+//=======================================================================
+
+bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
+ const bool the13Diag)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ MESSAGE( "::QuadToTri()" );
+
+ SMESHDS_Mesh * aMesh = GetMeshDS();
+
+ Handle(Geom_Surface) surface;
+ SMESH_MesherHelper helper( *GetMesh() );
+
+ TIDSortedElemSet::iterator itElem;
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() != SMDSAbs_Face )
+ continue;
+ bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
+ if(!isquad) continue;
+
+ if(elem->NbNodes()==4) {
+ // retrieve element nodes
+ const SMDS_MeshNode* aNodes [4];
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ int i = 0;
+ while ( itN->more() )
+ aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+
+ int aShapeId = FindShape( elem );
+ const SMDS_MeshElement* newElem1 = 0;
+ const SMDS_MeshElement* newElem2 = 0;
+ if ( the13Diag ) {
+ newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
+ newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
+ }
+ else {
+ newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
+ newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
+ }
+ myLastCreatedElems.Append(newElem1);
+ myLastCreatedElems.Append(newElem2);
+ // put a new triangle on the same shape and add to the same groups
+ if ( aShapeId )
+ {
+ aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+ aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+ }
+ AddToSameGroups( newElem1, elem, aMesh );
+ AddToSameGroups( newElem2, elem, aMesh );
+ //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
+ aMesh->RemoveElement( elem );
+ }
+
+ // Quadratic quadrangle
+
+ if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
+
+ // get surface elem is on
+ int aShapeId = FindShape( elem );
+ if ( aShapeId != helper.GetSubShapeID() ) {
+ surface.Nullify();
+ TopoDS_Shape shape;
+ if ( aShapeId > 0 )
+ shape = aMesh->IndexToShape( aShapeId );
+ if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
+ TopoDS_Face face = TopoDS::Face( shape );
+ surface = BRep_Tool::Surface( face );
+ if ( !surface.IsNull() )
+ helper.SetSubShape( shape );
}
}
aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
{
inFaceNode = aNodes[ i-1 ];
- }
+ }
}
// find middle point for (0,1,2,3)
myLastCreatedNodes.Append(newN);
// create a new element
- const SMDS_MeshElement* newElem = 0;
+ const SMDS_MeshElement* newElem1 = 0;
+ const SMDS_MeshElement* newElem2 = 0;
const SMDS_MeshNode* N[6];
if ( the13Diag ) {
N[0] = aNodes[0];
N[3] = aNodes[4];
N[4] = aNodes[5];
N[5] = newN;
- newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
- aNodes[6], aNodes[7], newN );
+ newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
+ aNodes[6], aNodes[7], newN );
+ newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
+ newN, aNodes[4], aNodes[5] );
}
else {
N[0] = aNodes[1];
N[3] = aNodes[5];
N[4] = aNodes[6];
N[5] = newN;
- newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
- aNodes[7], aNodes[4], newN );
+ newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
+ aNodes[7], aNodes[4], newN );
+ newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
+ newN, aNodes[5], aNodes[6] );
}
- myLastCreatedElems.Append(newElem);
- aMesh->ChangeElementNodes( elem, N, 6 );
+ myLastCreatedElems.Append(newElem1);
+ myLastCreatedElems.Append(newElem2);
// put a new triangle on the same shape and add to the same groups
if ( aShapeId )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- AddToSameGroups( newElem, elem, aMesh );
+ {
+ aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+ aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+ }
+ AddToSameGroups( newElem1, elem, aMesh );
+ AddToSameGroups( newElem2, elem, aMesh );
+ aMesh->RemoveElement( elem );
}
}
int i = 0, iDiag = -1;
while ( it->more()) {
const SMDS_MeshElement *n = it->next();
- if ( n == n1 || n == n2 )
+ if ( n == n1 || n == n2 ) {
if ( iDiag < 0)
iDiag = i;
else {
nFirst[ t ] = n;
break;
}
+ }
i++;
}
}
// and able to return nodes by that ID
// =================================================
class LinkID_Gen {
- public:
+public:
LinkID_Gen( const SMESHDS_Mesh* theMesh )
:myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
return true;
}
- private:
+private:
LinkID_Gen();
const SMESHDS_Mesh* myMesh;
long myMaxID;
// fusion is still performed.
//=======================================================================
-bool SMESH_MeshEditor::TriToQuad (map<int,const SMDS_MeshElement*> & theElems,
+bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
SMESH::Controls::NumericalFunctorPtr theCrit,
const double theMaxAngle)
{
return false;
SMESHDS_Mesh * aMesh = GetMeshDS();
- //LinkID_Gen aLinkID_Gen( aMesh );
// Prepare data for algo: build
// 1. map of elements with their linkIDs
// 2. map of linkIDs with their elements
- //map< long, list< const SMDS_MeshElement* > > mapLi_listEl;
- //map< long, list< const SMDS_MeshElement* > >::iterator itLE;
- //map< const SMDS_MeshElement*, set< long > > mapEl_setLi;
- //map< const SMDS_MeshElement*, set< long > >::iterator itEL;
+ map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
+ map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
+ map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
+ map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
- map< NLink, list< const SMDS_MeshElement* > > mapLi_listEl;
- map< NLink, list< const SMDS_MeshElement* > >::iterator itLE;
- map< const SMDS_MeshElement*, set< NLink > > mapEl_setLi;
- map< const SMDS_MeshElement*, set< NLink > >::iterator itEL;
-
- map<int,const SMDS_MeshElement*>::iterator itElem;
+ TIDSortedElemSet::iterator itElem;
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- const SMDS_MeshElement* elem = (*itElem).second;
- //if ( !elem || elem->NbNodes() != 3 )
- // continue;
+ const SMDS_MeshElement* elem = *itElem;
if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
if(!IsTria) continue;
const SMDS_MeshNode* aNodes [4];
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
int i = 0;
- //while ( itN->more() )
while ( i<3 )
- aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
- ASSERT( i == 3 );
+ aNodes[ i++ ] = cast2Node( itN->next() );
aNodes[ 3 ] = aNodes[ 0 ];
// fill maps
for ( i = 0; i < 3; i++ ) {
- //long linkID = aLinkID_Gen.GetLinkID( aNodes[ i ], aNodes[ i+1 ] );
- NLink link(( aNodes[i] < aNodes[i+1] ? aNodes[i] : aNodes[i+1] ),
- ( aNodes[i] < aNodes[i+1] ? aNodes[i+1] : aNodes[i] ));
+ SMESH_TLink link( aNodes[i], aNodes[i+1] );
// check if elements sharing a link can be fused
- //itLE = mapLi_listEl.find( linkID );
itLE = mapLi_listEl.find( link );
if ( itLE != mapLi_listEl.end() ) {
if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
(*itLE).second.push_back( elem );
}
else {
- //mapLi_listEl[ linkID ].push_back( elem );
mapLi_listEl[ link ].push_back( elem );
}
- //mapEl_setLi [ elem ].insert( linkID );
mapEl_setLi [ elem ].insert( link );
}
}
int nbElems = (*itLE).second.size();
if ( nbElems < 2 ) {
const SMDS_MeshElement* elem = (*itLE).second.front();
- //long link = (*itLE).first;
- NLink link = (*itLE).first;
+ SMESH_TLink link = (*itLE).first;
mapEl_setLi[ elem ].erase( link );
if ( mapEl_setLi[ elem ].empty() )
mapEl_setLi.erase( elem );
while ( ! mapEl_setLi.empty() ) {
// Look for the start element:
// the element having the least nb of shared links
-
const SMDS_MeshElement* startElem = 0;
int minNbLinks = 4;
for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
// search elements to fuse starting from startElem or links of elements
// fused earlyer - startLinks
- //list< long > startLinks;
- list< NLink > startLinks;
+ list< SMESH_TLink > startLinks;
while ( startElem || !startLinks.empty() ) {
while ( !startElem && !startLinks.empty() ) {
// Get an element to start, by a link
- //long linkId = startLinks.front();
- NLink linkId = startLinks.front();
+ SMESH_TLink linkId = startLinks.front();
startLinks.pop_front();
itLE = mapLi_listEl.find( linkId );
if ( itLE != mapLi_listEl.end() ) {
if ( startElem ) {
// Get candidates to be fused
const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
- //long link12, link13;
- NLink link12, link13;
+ const SMESH_TLink *link12, *link13;
startElem = 0;
ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
- //set< long >& setLi = mapEl_setLi[ tr1 ];
- set< NLink >& setLi = mapEl_setLi[ tr1 ];
+ set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
ASSERT( !setLi.empty() );
- //set< long >::iterator itLi;
- set< NLink >::iterator itLi;
- for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ ) {
- //long linkID = (*itLi);
- NLink linkID = (*itLi);
- itLE = mapLi_listEl.find( linkID );
+ set< SMESH_TLink >::iterator itLi;
+ for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
+ {
+ const SMESH_TLink & link = (*itLi);
+ itLE = mapLi_listEl.find( link );
if ( itLE == mapLi_listEl.end() )
continue;
continue;
if ( tr2 ) {
tr3 = elem;
- link13 = linkID;
+ link13 = &link;
}
else {
tr2 = elem;
- link12 = linkID;
+ link12 = &link;
}
// add other links of elem to list of links to re-start from
- //set< long >& links = mapEl_setLi[ elem ];
- //set< long >::iterator it;
- set< NLink >& links = mapEl_setLi[ elem ];
- set< NLink >::iterator it;
+ set< SMESH_TLink >& links = mapEl_setLi[ elem ];
+ set< SMESH_TLink >::iterator it;
for ( it = links.begin(); it != links.end(); it++ ) {
- //long linkID2 = (*it);
- NLink linkID2 = (*it);
- if ( linkID2 != linkID )
- startLinks.push_back( linkID2 );
+ const SMESH_TLink& link2 = (*it);
+ if ( link2 != link )
+ startLinks.push_back( link2 );
}
}
// Get nodes of possible quadrangles
const SMDS_MeshNode *n12 [4], *n13 [4];
bool Ok12 = false, Ok13 = false;
- //const SMDS_MeshNode *linkNode1, *linkNode2;
const SMDS_MeshNode *linkNode1, *linkNode2;
if(tr2) {
- //const SMDS_MeshNode *linkNode1 = link12.first;
- //const SMDS_MeshNode *linkNode2 = link12.second;
- linkNode1 = link12.first;
- linkNode2 = link12.second;
- //if ( tr2 &&
- // aLinkID_Gen.GetNodes( link12, linkNode1, linkNode2 ) &&
- // getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
- // Ok12 = true;
+ linkNode1 = link12->first;
+ linkNode2 = link12->second;
if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
Ok12 = true;
}
if(tr3) {
- linkNode1 = link13.first;
- linkNode2 = link13.second;
- //if ( tr3 &&
- // aLinkID_Gen.GetNodes( link13, linkNode1, linkNode2 ) &&
- // getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
- // Ok13 = true;
+ linkNode1 = link13->first;
+ linkNode2 = link13->second;
if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
Ok13 = true;
}
mapEl_setLi.erase( tr1 );
if ( Ok12 ) {
mapEl_setLi.erase( tr2 );
- mapLi_listEl.erase( link12 );
+ mapLi_listEl.erase( *link12 );
if(tr1->NbNodes()==3) {
- if( tr1->GetID() < tr2->GetID() ) {
- aMesh->ChangeElementNodes( tr1, n12, 4 );
- myLastCreatedElems.Append(tr1);
- aMesh->RemoveElement( tr2 );
- }
- else {
- aMesh->ChangeElementNodes( tr2, n12, 4 );
- myLastCreatedElems.Append(tr2);
- aMesh->RemoveElement( tr1);
- }
+ const SMDS_MeshElement* newElem = 0;
+ newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
+ myLastCreatedElems.Append(newElem);
+ AddToSameGroups( newElem, tr1, aMesh );
+ int aShapeId = tr1->getshapeId();
+ if ( aShapeId )
+ {
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ aMesh->RemoveElement( tr1 );
+ aMesh->RemoveElement( tr2 );
}
else {
const SMDS_MeshNode* N1 [6];
const SMDS_MeshNode* N2 [6];
GetNodesFromTwoTria(tr1,tr2,N1,N2);
// now we receive following N1 and N2 (using numeration as above image)
- // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
+ // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
// i.e. first nodes from both arrays determ new diagonal
const SMDS_MeshNode* aNodes[8];
aNodes[0] = N1[0];
aNodes[5] = N2[5];
aNodes[6] = N2[3];
aNodes[7] = N1[5];
- if( tr1->GetID() < tr2->GetID() ) {
- GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
- myLastCreatedElems.Append(tr1);
- GetMeshDS()->RemoveElement( tr2 );
- }
- else {
- GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
- myLastCreatedElems.Append(tr2);
- GetMeshDS()->RemoveElement( tr1 );
- }
+ const SMDS_MeshElement* newElem = 0;
+ newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+ aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+ myLastCreatedElems.Append(newElem);
+ AddToSameGroups( newElem, tr1, aMesh );
+ int aShapeId = tr1->getshapeId();
+ if ( aShapeId )
+ {
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ aMesh->RemoveElement( tr1 );
+ aMesh->RemoveElement( tr2 );
// remove middle node (9)
GetMeshDS()->RemoveNode( N1[4] );
}
}
else if ( Ok13 ) {
mapEl_setLi.erase( tr3 );
- mapLi_listEl.erase( link13 );
+ mapLi_listEl.erase( *link13 );
if(tr1->NbNodes()==3) {
- if( tr1->GetID() < tr2->GetID() ) {
- aMesh->ChangeElementNodes( tr1, n13, 4 );
- myLastCreatedElems.Append(tr1);
- aMesh->RemoveElement( tr3 );
- }
- else {
- aMesh->ChangeElementNodes( tr3, n13, 4 );
- myLastCreatedElems.Append(tr3);
- aMesh->RemoveElement( tr1 );
- }
+ const SMDS_MeshElement* newElem = 0;
+ newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
+ myLastCreatedElems.Append(newElem);
+ AddToSameGroups( newElem, tr1, aMesh );
+ int aShapeId = tr1->getshapeId();
+ if ( aShapeId )
+ {
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ aMesh->RemoveElement( tr1 );
+ aMesh->RemoveElement( tr3 );
}
else {
const SMDS_MeshNode* N1 [6];
const SMDS_MeshNode* N2 [6];
GetNodesFromTwoTria(tr1,tr3,N1,N2);
// now we receive following N1 and N2 (using numeration as above image)
- // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
+ // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
// i.e. first nodes from both arrays determ new diagonal
const SMDS_MeshNode* aNodes[8];
aNodes[0] = N1[0];
aNodes[5] = N2[5];
aNodes[6] = N2[3];
aNodes[7] = N1[5];
- if( tr1->GetID() < tr2->GetID() ) {
- GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
- myLastCreatedElems.Append(tr1);
- GetMeshDS()->RemoveElement( tr3 );
- }
- else {
- GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
- myLastCreatedElems.Append(tr3);
- GetMeshDS()->RemoveElement( tr1 );
- }
+ const SMDS_MeshElement* newElem = 0;
+ newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+ aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+ myLastCreatedElems.Append(newElem);
+ AddToSameGroups( newElem, tr1, aMesh );
+ int aShapeId = tr1->getshapeId();
+ if ( aShapeId )
+ {
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ aMesh->RemoveElement( tr1 );
+ aMesh->RemoveElement( tr3 );
// remove middle node (9)
GetMeshDS()->RemoveNode( N1[4] );
}
//=============================================================================
static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
{
- if ( i1 == i2 )
- return;
- int tmp = idNodes[ i1 ];
- idNodes[ i1 ] = idNodes[ i2 ];
- idNodes[ i2 ] = tmp;
- gp_Pnt Ptmp = P[ i1 ];
- P[ i1 ] = P[ i2 ];
- P[ i2 ] = Ptmp;
- DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
+if ( i1 == i2 )
+return;
+int tmp = idNodes[ i1 ];
+idNodes[ i1 ] = idNodes[ i2 ];
+idNodes[ i2 ] = tmp;
+gp_Pnt Ptmp = P[ i1 ];
+P[ i1 ] = P[ i2 ];
+P[ i2 ] = Ptmp;
+DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
}
//=======================================================================
//=======================================================================
int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
- int idNodes[] )
+int idNodes[] )
{
gp_Pnt P[4];
int i;
i = 1;
swap ( i, i + 1, idNodes, P );
-// for ( int ii = 0; ii < 4; ii++ ) {
-// const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
-// DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
-// }
+ // for ( int ii = 0; ii < 4; ii++ ) {
+ // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
+ // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
+ // }
}
return i;
}
faceNodes.insert( idNodes[ 2 ] );
faceNodes.insert( idNodes[ iMin ] );
DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
- << " leastDist = " << leastDist);
+ << " leastDist = " << leastDist);
if ( leastDist <= DBL_MIN )
break;
}
P[ i ] = P[ i+1 ];
P[ i+1 ] = Ptmp;
}
-// else
-// for ( int ii = 0; ii < 4; ii++ ) {
-// const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
-// DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
-// }
+ // else
+ // for ( int ii = 0; ii < 4; ii++ ) {
+ // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
+ // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
+ // }
// Gravity center of the top and bottom faces
gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
swap( 5, 7, idNodes, P );
}
-// DUMPSO( "OUTPUT: ========================================");
-// for ( i = 0; i < 8; i++ ) {
-// float *p = ugrid->GetPoint(idNodes[i]);
-// DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
-// }
+ // DUMPSO( "OUTPUT: ========================================");
+ // for ( i = 0; i < 8; i++ ) {
+ // float *p = ugrid->GetPoint(idNodes[i]);
+ // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
+ // }
return true;
}*/
+//================================================================================
+/*!
+ * \brief Return nodes linked to the given one
+ * \param theNode - the node
+ * \param linkedNodes - the found nodes
+ * \param type - the type of elements to check
+ *
+ * Medium nodes are ignored
+ */
+//================================================================================
+
+void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
+ TIDSortedElemSet & linkedNodes,
+ SMDSAbs_ElementType type )
+{
+ SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* elem = elemIt->next();
+ SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+ if ( elem->GetType() == SMDSAbs_Volume )
+ {
+ SMDS_VolumeTool vol( elem );
+ while ( nodeIt->more() ) {
+ const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+ if ( theNode != n && vol.IsLinked( theNode, n ))
+ linkedNodes.insert( n );
+ }
+ }
+ else
+ {
+ for ( int i = 0; nodeIt->more(); ++i ) {
+ const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+ if ( n == theNode ) {
+ int iBefore = i - 1;
+ int iAfter = i + 1;
+ if ( elem->IsQuadratic() ) {
+ int nb = elem->NbNodes() / 2;
+ iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
+ iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
+ }
+ linkedNodes.insert( elem->GetNodeWrap( iAfter ));
+ linkedNodes.insert( elem->GetNodeWrap( iBefore ));
+ }
+ }
+ }
+ }
+}
+
//=======================================================================
//function : laplacianSmooth
//purpose : pulls theNode toward the center of surrounding nodes directly
{
// find surrounding nodes
- set< const SMDS_MeshNode* > nodeSet;
- SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
- while ( elemIt->more() )
- {
- const SMDS_MeshElement* elem = elemIt->next();
- if ( elem->GetType() != SMDSAbs_Face )
- continue;
-
- for ( int i = 0; i < elem->NbNodes(); ++i ) {
- if ( elem->GetNode( i ) == theNode ) {
- // add linked nodes
- int iBefore = i - 1;
- int iAfter = i + 1;
- if ( elem->IsQuadratic() ) {
- int nbCorners = elem->NbNodes() / 2;
- if ( iAfter >= nbCorners )
- iAfter = 0; // elem->GetNode() wraps index
- if ( iBefore == -1 )
- iBefore = nbCorners - 1;
- }
- nodeSet.insert( elem->GetNode( iAfter ));
- nodeSet.insert( elem->GetNode( iBefore ));
- break;
- }
- }
- }
+ TIDSortedElemSet nodeSet;
+ SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
// compute new coodrs
double coord[] = { 0., 0., 0. };
- set< const SMDS_MeshNode* >::iterator nodeSetIt = nodeSet.begin();
+ TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
- const SMDS_MeshNode* node = (*nodeSetIt);
+ const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
if ( theSurface.IsNull() ) { // smooth in 3D
coord[0] += node->X();
coord[1] += node->Y();
// compute new XYZ
- SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
+ SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
while ( elemIt->more() )
{
const SMDS_MeshElement* elem = elemIt->next();
- if ( elem->GetType() != SMDSAbs_Face )
- continue;
nbElems++;
gp_XYZ elemCenter(0.,0.,0.);
// on edges and boundary nodes are always fixed.
//=======================================================================
-void SMESH_MeshEditor::Smooth (map<int,const SMDS_MeshElement*> & theElems,
- set<const SMDS_MeshNode*> & theFixedNodes,
- const SmoothMethod theSmoothMethod,
- const int theNbIterations,
- double theTgtAspectRatio,
- const bool the2D)
+void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
+ set<const SMDS_MeshNode*> & theFixedNodes,
+ const SmoothMethod theSmoothMethod,
+ const int theNbIterations,
+ double theTgtAspectRatio,
+ const bool the2D)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
while ( fIt->more() ) {
const SMDS_MeshElement* face = fIt->next();
- theElems.insert( make_pair(face->GetID(),face) );
+ theElems.insert( face );
}
}
// get all face ids theElems are on
set< int > faceIdSet;
- map<int, const SMDS_MeshElement* >::iterator itElem;
+ TIDSortedElemSet::iterator itElem;
if ( the2D )
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- int fId = FindShape( (*itElem).second );
+ int fId = FindShape( *itElem );
// check that corresponding submesh exists and a shape is face
if (fId &&
faceIdSet.find( fId ) == faceIdSet.end() &&
}
int nbElemOnFace = 0;
itElem = theElems.begin();
- // loop on not yet smoothed elements: look for elems on a face
+ // loop on not yet smoothed elements: look for elems on a face
while ( itElem != theElems.end() ) {
if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
break; // all elements found
- const SMDS_MeshElement* elem = (*itElem).second;
+ const SMDS_MeshElement* elem = *itElem;
if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
- ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
+ ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
++itElem;
continue;
}
while ( nn++ < nbn ) {
node = static_cast<const SMDS_MeshNode*>( itN->next() );
const SMDS_PositionPtr& pos = node->GetPosition();
- posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
+ posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
if (posType != SMDS_TOP_EDGE &&
posType != SMDS_TOP_VERTEX &&
theFixedNodes.find( node ) == theFixedNodes.end())
{
// check if all faces around the node are on faceSubMesh
// because a node on edge may be bound to face
- SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
+ SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
bool all = true;
if ( faceSubMesh ) {
while ( eIt->more() && all ) {
const SMDS_MeshElement* e = eIt->next();
- if ( e->GetType() == SMDSAbs_Face )
- all = faceSubMesh->Contains( e );
+ all = faceSubMesh->Contains( e );
}
}
if ( all )
if ( uvMap.find( node ) == uvMap.end() )
uvCheckNodes.push_back( node );
// add nodes of elems sharing node
-// SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
-// while ( eIt->more() ) {
-// const SMDS_MeshElement* e = eIt->next();
-// if ( e != elem && e->GetType() == SMDSAbs_Face ) {
-// SMDS_ElemIteratorPtr nIt = e->nodesIterator();
-// while ( nIt->more() ) {
-// const SMDS_MeshNode* n =
-// static_cast<const SMDS_MeshNode*>( nIt->next() );
-// if ( uvMap.find( n ) == uvMap.end() )
-// uvCheckNodes.push_back( n );
-// }
-// }
-// }
+ // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
+ // while ( eIt->more() ) {
+ // const SMDS_MeshElement* e = eIt->next();
+ // if ( e != elem ) {
+ // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
+ // while ( nIt->more() ) {
+ // const SMDS_MeshNode* n =
+ // static_cast<const SMDS_MeshNode*>( nIt->next() );
+ // if ( uvMap.find( n ) == uvMap.end() )
+ // uvCheckNodes.push_back( n );
+ // }
+ // }
+ // }
}
// check UV on face
list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
node = *n;
gp_XY uv( 0, 0 );
const SMDS_PositionPtr& pos = node->GetPosition();
- posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
+ posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
// get existing UV
switch ( posType ) {
case SMDS_TOP_FACE: {
- SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
+ SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
break;
}
case SMDS_TOP_EDGE: {
- TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
+ TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
Handle(Geom2d_Curve) pcurve;
if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
if ( !pcurve.IsNull() ) {
- double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
+ double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
uv = pcurve->Value( u ).XY();
}
break;
}
case SMDS_TOP_VERTEX: {
- TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
+ TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
break;
// fix nodes on mesh boundary
if ( checkBoundaryNodes ) {
- typedef pair<const SMDS_MeshNode*, const SMDS_MeshNode*> TLink;
- map< TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
- map< TLink, int >::iterator link_nb;
+ map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
+ map< NLink, int >::iterator link_nb;
// put all elements links to linkNbMap
list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
if(elem->IsQuadratic())
nbn = nbn/2;
// loop on elem links: insert them in linkNbMap
- const SMDS_MeshNode* curNode, *prevNode = elem->GetNode( nbn );
+ const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
for ( int iN = 0; iN < nbn; ++iN ) {
curNode = elem->GetNode( iN );
- TLink link;
+ NLink link;
if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
else link = make_pair( prevNode , curNode );
prevNode = curNode;
uvMap2[ nSeam ] = &listUV.back();
// collect movable nodes linked to ones on seam in nodesNearSeam
- SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator();
+ SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
while ( eIt->more() ) {
const SMDS_MeshElement* e = eIt->next();
- if ( e->GetType() != SMDSAbs_Face )
- continue;
int nbUseMap1 = 0, nbUseMap2 = 0;
SMDS_ElemIteratorPtr nIt = e->nodesIterator();
int nn = 0, nbn = e->NbNodes();
if ( node_uv != uvMap.end() ) {
gp_XY* uv = node_uv->second;
node->SetPosition
- ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
+ ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
}
}
helper.SetSubShape( face );
list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
- const SMDS_QuadraticFaceOfNodes* QF =
- dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
- if(QF) {
+ const SMDS_VtkFace* QF =
+ dynamic_cast<const SMDS_VtkFace*> (*elemIt);
+ if(QF && QF->IsQuadratic()) {
vector<const SMDS_MeshNode*> Ns;
Ns.reserve(QF->NbNodes()+1);
- SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
+ SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
while ( anIter->more() )
- Ns.push_back( anIter->next() );
+ Ns.push_back( cast2Node(anIter->next()) );
Ns.push_back( Ns[0] );
double x, y, z;
for(int i=0; i<QF->NbNodes(); i=i+2) {
gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
gp_XY uv = ( uv1 + uv2 ) / 2.;
gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
- x = xyz.X(); y = xyz.Y(); z = xyz.Z();
+ x = xyz.X(); y = xyz.Y(); z = xyz.Z();
}
else {
x = (Ns[i]->X() + Ns[i+2]->X())/2;
}
}
}
-
+
} // loop on face ids
}
// iNotSame is where prevNodes and nextNodes are different
//=======================================================================
-static bool isReverse(const SMDS_MeshNode* prevNodes[],
- const SMDS_MeshNode* nextNodes[],
+static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
+ vector<const SMDS_MeshNode*> nextNodes,
const int nbNodes,
const int iNotSame)
{
}
//=======================================================================
-//function : sweepElement
-//purpose :
+/*!
+ * \brief Create elements by sweeping an element
+ * \param elem - element to sweep
+ * \param newNodesItVec - nodes generated from each node of the element
+ * \param newElems - generated elements
+ * \param nbSteps - number of sweeping steps
+ * \param srcElements - to append elem for each generated element
+ */
//=======================================================================
-static void sweepElement(SMESHDS_Mesh* aMesh,
- const SMDS_MeshElement* elem,
- const vector<TNodeOfNodeListMapItr> & newNodesItVec,
- list<const SMDS_MeshElement*>& newElems,
- const int nbSteps,
- SMESH_SequenceOfElemPtr& myLastCreatedElems)
+void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
+ const vector<TNodeOfNodeListMapItr> & newNodesItVec,
+ list<const SMDS_MeshElement*>& newElems,
+ const int nbSteps,
+ SMESH_SequenceOfElemPtr& srcElements)
{
+ //MESSAGE("sweepElement " << nbSteps);
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
// Loop on elem nodes:
// find new nodes and detect same nodes indices
int nbNodes = elem->NbNodes();
- list<const SMDS_MeshNode*>::const_iterator itNN[ nbNodes ];
- const SMDS_MeshNode* prevNod[ nbNodes ], *nextNod[ nbNodes ], *midlNod[ nbNodes ];
+ vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
+ vector<const SMDS_MeshNode*> prevNod( nbNodes );
+ vector<const SMDS_MeshNode*> nextNod( nbNodes );
+ vector<const SMDS_MeshNode*> midlNod( nbNodes );
+
int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
vector<int> sames(nbNodes);
-
- bool issimple[nbNodes];
+ vector<bool> issimple(nbNodes);
for ( iNode = 0; iNode < nbNodes; iNode++ ) {
TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
const SMDS_MeshNode* node = nnIt->first;
const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
- if ( listNewNodes.empty() )
+ if ( listNewNodes.empty() ) {
return;
-
- if(listNewNodes.size()==nbSteps) {
- issimple[iNode] = true;
- }
- else {
- issimple[iNode] = false;
}
+ issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
+
itNN[ iNode ] = listNewNodes.begin();
prevNod[ iNode ] = node;
nextNod[ iNode ] = listNewNodes.front();
-//cout<<"iNode="<<iNode<<endl;
-//cout<<" prevNod[iNode]="<< prevNod[iNode]<<" nextNod[iNode]="<< nextNod[iNode]<<endl;
- if ( prevNod[ iNode ] != nextNod [ iNode ])
- iNotSameNode = iNode;
- else {
- iSameNode = iNode;
- //nbSame++;
- sames[nbSame++] = iNode;
+ if( !elem->IsQuadratic() || !issimple[iNode] ) {
+ if ( prevNod[ iNode ] != nextNod [ iNode ])
+ iNotSameNode = iNode;
+ else {
+ iSameNode = iNode;
+ //nbSame++;
+ sames[nbSame++] = iNode;
+ }
}
}
-//cout<<"1 nbSame="<<nbSame<<endl;
+
+ //cerr<<" nbSame = "<<nbSame<<endl;
if ( nbSame == nbNodes || nbSame > 2) {
MESSAGE( " Too many same nodes of element " << elem->GetID() );
+ //INFOS( " Too many same nodes of element " << elem->GetID() );
return;
}
-// if( elem->IsQuadratic() && nbSame>0 ) {
-// MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
-// return;
-// }
+ // if( elem->IsQuadratic() && nbSame>0 ) {
+ // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
+ // return;
+ // }
int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
+ int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
if ( nbSame > 0 ) {
- iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 );
- iAfterSame = ( iSameNode + 1 == nbNodes ? 0 : iSameNode + 1 );
+ iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
+ iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
}
-//if(nbNodes==8)
-//cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
-// <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
-// <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
-// <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
+ //if(nbNodes==8)
+ //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
+ // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
+ // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
+ // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
// check element orientation
int i0 = 0, i2 = 2;
//MESSAGE("Reversed elem " << elem );
i0 = 2;
i2 = 0;
- if ( nbSame > 0 ) {
- int iAB = iAfterSame + iBeforeSame;
- iBeforeSame = iAB - iBeforeSame;
- iAfterSame = iAB - iAfterSame;
- }
+ if ( nbSame > 0 )
+ std::swap( iBeforeSame, iAfterSame );
}
// make new elements
- int iStep;//, nbSteps = newNodesItVec[ 0 ]->second.size();
- for (iStep = 0; iStep < nbSteps; iStep++ ) {
+ const SMDS_MeshElement* lastElem = elem;
+ for (int iStep = 0; iStep < nbSteps; iStep++ ) {
// get next nodes
for ( iNode = 0; iNode < nbNodes; iNode++ ) {
if(issimple[iNode]) {
nextNod[ iNode ] = *itNN[ iNode ];
itNN[ iNode ]++;
}
- else if(!elem->IsQuadratic() ||
- elem->IsQuadratic() && elem->IsMediumNode(prevNod[iNode]) ) {
+ else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
// we have to use each second node
- itNN[ iNode ]++;
+ //itNN[ iNode ]++;
nextNod[ iNode ] = *itNN[ iNode ];
itNN[ iNode ]++;
}
midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
}
else if(nbSame==1) { // quadratic triangle
- if(sames[0]==2)
+ if(sames[0]==2) {
return; // medium node on axis
+ }
else if(sames[0]==0) {
aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
nextNod[2], midlNod[1], prevNod[2]);
midlNod[0], nextNod[2], prevNod[2]);
}
}
- else
+ else {
return;
+ }
}
break;
}
if ( nbSame == 0 ) // --- hexahedron
aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
-
+
else if ( nbSame == 1 ) { // --- pyramid + pentahedron
aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
}
case 6: { // quadratic triangle
// create pentahedron with 15 nodes
- if(i0>0) { // reversed case
- aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
- nextNod[0], nextNod[2], nextNod[1],
- prevNod[5], prevNod[4], prevNod[3],
- nextNod[5], nextNod[4], nextNod[3],
- midlNod[0], midlNod[2], midlNod[1]);
- }
- else { // not reversed case
- aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
- nextNod[0], nextNod[1], nextNod[2],
- prevNod[3], prevNod[4], prevNod[5],
- nextNod[3], nextNod[4], nextNod[5],
- midlNod[0], midlNod[1], midlNod[2]);
+ if(nbSame==0) {
+ if(i0>0) { // reversed case
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
+ nextNod[0], nextNod[2], nextNod[1],
+ prevNod[5], prevNod[4], prevNod[3],
+ nextNod[5], nextNod[4], nextNod[3],
+ midlNod[0], midlNod[2], midlNod[1]);
+ }
+ else { // not reversed case
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
+ nextNod[0], nextNod[1], nextNod[2],
+ prevNod[3], prevNod[4], prevNod[5],
+ nextNod[3], nextNod[4], nextNod[5],
+ midlNod[0], midlNod[1], midlNod[2]);
+ }
+ }
+ else if(nbSame==1) {
+ // 2d order pyramid of 13 nodes
+ //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
+ // int n12,int n23,int n34,int n41,
+ // int n15,int n25,int n35,int n45, int ID);
+ int n5 = iSameNode;
+ int n1,n4,n41,n15,n45;
+ if(i0>0) { // reversed case
+ n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
+ n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
+ n41 = n1 + 3;
+ n15 = n5 + 3;
+ n45 = n4 + 3;
+ }
+ else {
+ n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
+ n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
+ n41 = n4 + 3;
+ n15 = n1 + 3;
+ n45 = n5 + 3;
+ }
+ aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
+ nextNod[n4], prevNod[n4], prevNod[n5],
+ midlNod[n1], nextNod[n41],
+ midlNod[n4], prevNod[n41],
+ prevNod[n15], nextNod[n15],
+ nextNod[n45], prevNod[n45]);
+ }
+ else if(nbSame==2) {
+ // 2d order tetrahedron of 10 nodes
+ //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
+ // int n12,int n23,int n31,
+ // int n14,int n24,int n34, int ID);
+ int n1 = iNotSameNode;
+ int n2,n3,n12,n23,n31;
+ if(i0>0) { // reversed case
+ n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
+ n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
+ n12 = n2 + 3;
+ n23 = n3 + 3;
+ n31 = n1 + 3;
+ }
+ else {
+ n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
+ n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
+ n12 = n1 + 3;
+ n23 = n2 + 3;
+ n31 = n3 + 3;
+ }
+ aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
+ prevNod[n12], prevNod[n23], prevNod[n31],
+ midlNod[n1], nextNod[n12], nextNod[n31]);
}
break;
}
case 8: { // quadratic quadrangle
- // create hexahedron with 20 nodes
- if(i0>0) { // reversed case
- aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
- nextNod[0], nextNod[3], nextNod[2], nextNod[1],
- prevNod[7], prevNod[6], prevNod[5], prevNod[4],
- nextNod[7], nextNod[6], nextNod[5], nextNod[4],
- midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
- }
- else { // not reversed case
- aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
- nextNod[0], nextNod[1], nextNod[2], nextNod[3],
- prevNod[4], prevNod[5], prevNod[6], prevNod[7],
- nextNod[4], nextNod[5], nextNod[6], nextNod[7],
- midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
+ if(nbSame==0) {
+ // create hexahedron with 20 nodes
+ if(i0>0) { // reversed case
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
+ nextNod[0], nextNod[3], nextNod[2], nextNod[1],
+ prevNod[7], prevNod[6], prevNod[5], prevNod[4],
+ nextNod[7], nextNod[6], nextNod[5], nextNod[4],
+ midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
+ }
+ else { // not reversed case
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
+ nextNod[0], nextNod[1], nextNod[2], nextNod[3],
+ prevNod[4], prevNod[5], prevNod[6], prevNod[7],
+ nextNod[4], nextNod[5], nextNod[6], nextNod[7],
+ midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
+ }
+ }
+ else if(nbSame==1) {
+ // --- pyramid + pentahedron - can not be created since it is needed
+ // additional middle node ot the center of face
+ INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
+ return;
+ }
+ else if(nbSame==2) {
+ // 2d order Pentahedron with 15 nodes
+ //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
+ // int n12,int n23,int n31,int n45,int n56,int n64,
+ // int n14,int n25,int n36, int ID);
+ int n1,n2,n4,n5;
+ if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
+ // iBeforeSame is same too
+ n1 = iBeforeSame;
+ n2 = iOpposSame;
+ n4 = iSameNode;
+ n5 = iAfterSame;
+ }
+ else {
+ // iAfterSame is same too
+ n1 = iSameNode;
+ n2 = iBeforeSame;
+ n4 = iAfterSame;
+ n5 = iOpposSame;
+ }
+ int n12,n45,n14,n25;
+ if(i0>0) { //reversed case
+ n12 = n1 + 4;
+ n45 = n5 + 4;
+ n14 = n4 + 4;
+ n25 = n2 + 4;
+ }
+ else {
+ n12 = n2 + 4;
+ n45 = n4 + 4;
+ n14 = n1 + 4;
+ n25 = n5 + 4;
+ }
+ aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
+ prevNod[n4], prevNod[n5], nextNod[n5],
+ prevNod[n12], midlNod[n2], nextNod[n12],
+ prevNod[n45], midlNod[n5], nextNod[n45],
+ prevNod[n14], prevNod[n25], nextNod[n25]);
}
break;
}
// realized for extrusion only
//vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
//vector<int> quantities (nbNodes + 2);
-
+
//quantities[0] = nbNodes; // bottom of prism
//for (int inode = 0; inode < nbNodes; inode++) {
// polyedre_nodes[inode] = prevNod[inode];
//for (int inode = 0; inode < nbNodes; inode++) {
// polyedre_nodes[nbNodes + inode] = nextNod[inode];
//}
-
+
//for (int iface = 0; iface < nbNodes; iface++) {
// quantities[iface + 2] = 4;
// int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
if ( aNewElem ) {
newElems.push_back( aNewElem );
myLastCreatedElems.Append(aNewElem);
+ srcElements.Append( elem );
+ lastElem = aNewElem;
}
// set new prev nodes
}
//=======================================================================
-//function : makeWalls
-//purpose : create 1D and 2D elements around swept elements
+/*!
+ * \brief Create 1D and 2D elements around swept elements
+ * \param mapNewNodes - source nodes and ones generated from them
+ * \param newElemsMap - source elements and ones generated from them
+ * \param elemNewNodesMap - nodes generated from each node of each element
+ * \param elemSet - all swept elements
+ * \param nbSteps - number of sweeping steps
+ * \param srcElements - to append elem for each generated element
+ */
//=======================================================================
-static void makeWalls (SMESHDS_Mesh* aMesh,
- TNodeOfNodeListMap & mapNewNodes,
- TElemOfElemListMap & newElemsMap,
- TElemOfVecOfNnlmiMap & elemNewNodesMap,
- map<int,const SMDS_MeshElement*>& elemSet,
- const int nbSteps,
- SMESH_SequenceOfElemPtr& myLastCreatedElems)
+void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
+ TElemOfElemListMap & newElemsMap,
+ TElemOfVecOfNnlmiMap & elemNewNodesMap,
+ TIDSortedElemSet& elemSet,
+ const int nbSteps,
+ SMESH_SequenceOfElemPtr& srcElements)
{
+ MESSAGE("makeWalls");
ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
+ SMESHDS_Mesh* aMesh = GetMeshDS();
// Find nodes belonging to only one initial element - sweep them to get edges.
static_cast<const SMDS_MeshNode*>( nList->first );
SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
int nbInitElems = 0;
- const SMDS_MeshElement* el;
+ const SMDS_MeshElement* el = 0;
+ SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
while ( eIt->more() && nbInitElems < 2 ) {
el = eIt->next();
- //if ( elemSet.find( eIt->next() ) != elemSet.end() )
- if ( elemSet.find(el->GetID()) != elemSet.end() )
+ SMDSAbs_ElementType type = el->GetType();
+ if ( type == SMDSAbs_Volume || type < highType ) continue;
+ if ( type > highType ) {
+ nbInitElems = 0;
+ highType = type;
+ }
+ if ( elemSet.find(el) != elemSet.end() )
nbInitElems++;
}
if ( nbInitElems < 2 ) {
- bool NotCreateEdge = el->IsQuadratic() && el->IsMediumNode(node);
+ bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
if(!NotCreateEdge) {
vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
list<const SMDS_MeshElement*> newEdges;
- sweepElement( aMesh, node, newNodesItVec, newEdges, nbSteps, myLastCreatedElems );
+ sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
}
}
}
const SMDS_MeshElement* elem = itElem->first;
vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
+ if(itElem->second.size()==0) continue;
+
if ( elem->GetType() == SMDSAbs_Edge ) {
- if(!elem->IsQuadratic()) {
- // create a ceiling edge
- myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
- vecNewNodes[ 1 ]->second.back()));
+ // create a ceiling edge
+ if (!elem->IsQuadratic()) {
+ if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back())) {
+ myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back()));
+ srcElements.Append( myLastCreatedElems.Last() );
+ }
}
else {
- // create a ceiling edge
- myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
- vecNewNodes[ 1 ]->second.back(),
- vecNewNodes[ 2 ]->second.back()));
+ if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back(),
+ vecNewNodes[ 2 ]->second.back())) {
+ myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back(),
+ vecNewNodes[ 2 ]->second.back()));
+ srcElements.Append( myLastCreatedElems.Last() );
+ }
}
}
if ( elem->GetType() != SMDSAbs_Face )
continue;
- if(itElem->second.size()==0) continue;
-
bool hasFreeLinks = false;
- map<int,const SMDS_MeshElement*> avoidSet;
- avoidSet.insert( make_pair(elem->GetID(),elem) );
+ TIDSortedElemSet avoidSet;
+ avoidSet.insert( elem );
set<const SMDS_MeshNode*> aFaceLastNodes;
int iNode, nbNodes = vecNewNodes.size();
if(!elem->IsQuadratic()) {
- // loop on a face nodes
+ // loop on the face nodes
for ( iNode = 0; iNode < nbNodes; iNode++ ) {
aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
- // look for free links of a face
+ // look for free links of the face
int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
hasFreeLinks = true;
// make an edge and a ceiling for a new edge
if ( !aMesh->FindEdge( n1, n2 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 ));
+ myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
+ srcElements.Append( myLastCreatedElems.Last() );
}
n1 = vecNewNodes[ iNode ]->second.back();
n2 = vecNewNodes[ iNext ]->second.back();
if ( !aMesh->FindEdge( n1, n2 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 ));
+ myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
+ srcElements.Append( myLastCreatedElems.Last() );
}
}
}
// find medium node
const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
if ( !aMesh->FindEdge( n1, n2, n3 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 ));
+ myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
+ srcElements.Append( myLastCreatedElems.Last() );
}
n1 = vecNewNodes[ iNode ]->second.back();
n2 = vecNewNodes[ iNext ]->second.back();
n3 = vecNewNodes[ iNode+nbn ]->second.back();
if ( !aMesh->FindEdge( n1, n2, n3 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 ));
+ myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
+ srcElements.Append( myLastCreatedElems.Last() );
}
}
}
if ( hasFreeLinks ) {
list<const SMDS_MeshElement*> & newVolumes = itElem->second;
- int iStep; //, nbSteps = vecNewNodes[0]->second.size();
int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
- set<const SMDS_MeshNode*> initNodeSet, faceNodeSet;
- for ( iNode = 0; iNode < nbNodes; iNode++ )
+ set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
+ for ( iNode = 0; iNode < nbNodes; iNode++ ) {
initNodeSet.insert( vecNewNodes[ iNode ]->first );
-
+ topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
+ }
for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
iVol = 0;
while ( iVol++ < volNb ) v++;
- // find indices of free faces of a volume
- list< int > fInd;
+ // find indices of free faces of a volume and their source edges
+ list< int > freeInd;
+ list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
SMDS_VolumeTool vTool( *v );
int iF, nbF = vTool.NbFaces();
for ( iF = 0; iF < nbF; iF ++ ) {
if (vTool.IsFreeFace( iF ) &&
vTool.GetFaceNodes( iF, faceNodeSet ) &&
initNodeSet != faceNodeSet) // except an initial face
- fInd.push_back( iF );
+ {
+ if ( nbSteps == 1 && faceNodeSet == topNodeSet )
+ continue;
+ freeInd.push_back( iF );
+ // find source edge of a free face iF
+ vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
+ commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
+ std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
+ initNodeSet.begin(), initNodeSet.end(),
+ commonNodes.begin());
+ if ( (*v)->IsQuadratic() )
+ srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
+ else
+ srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
+#ifdef _DEBUG_
+ if ( !srcEdges.back() )
+ {
+ cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
+ << iF << " of volume #" << vTool.ID() << endl;
+ }
+#endif
+ }
}
- if ( fInd.empty() )
+ if ( freeInd.empty() )
continue;
- // create faces for all steps
- for ( iStep = 0; iStep < nbSteps; iStep++ ) {
+ // create faces for all steps;
+ // if such a face has been already created by sweep of edge,
+ // assure that its orientation is OK
+ for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
vTool.Set( *v );
vTool.SetExternalNormal();
- list< int >::iterator ind = fInd.begin();
- for ( ; ind != fInd.end(); ind++ ) {
+ list< int >::iterator ind = freeInd.begin();
+ list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
+ for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
+ {
const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
int nbn = vTool.NbFaceNodes( *ind );
- //switch ( vTool.NbFaceNodes( *ind ) ) {
switch ( nbn ) {
- case 3:
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); break;
- case 4:
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] )); break;
+ case 3: { ///// triangle
+ const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
+ if ( !f )
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
+ else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+ {
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
+ aMesh->RemoveElement(f);
+ }
+ break;
+ }
+ case 4: { ///// quadrangle
+ const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
+ if ( !f )
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
+ else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+ {
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
+ aMesh->RemoveElement(f);
+ }
+ break;
+ }
default:
- {
- if( (*v)->IsQuadratic() ) {
- if(nbn==6) {
+ if( (*v)->IsQuadratic() ) {
+ if(nbn==6) { /////// quadratic triangle
+ const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5] );
+ if ( !f ) {
myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
- nodes[1], nodes[3], nodes[5])); break;
+ nodes[1], nodes[3], nodes[5]));
}
- else {
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7]));
- break;
+ else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
+ const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
+ tmpnodes[0] = nodes[0];
+ tmpnodes[1] = nodes[2];
+ tmpnodes[2] = nodes[4];
+ tmpnodes[3] = nodes[1];
+ tmpnodes[4] = nodes[3];
+ tmpnodes[5] = nodes[5];
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5]));
+ aMesh->RemoveElement(f);
}
}
- else {
- int nbPolygonNodes = vTool.NbFaceNodes( *ind );
- vector<const SMDS_MeshNode*> polygon_nodes (nbPolygonNodes);
- for (int inode = 0; inode < nbPolygonNodes; inode++) {
- polygon_nodes[inode] = nodes[inode];
+ else { /////// quadratic quadrangle
+ const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7] );
+ if ( !f ) {
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]));
+ }
+ else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
+ const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
+ tmpnodes[0] = nodes[0];
+ tmpnodes[1] = nodes[2];
+ tmpnodes[2] = nodes[4];
+ tmpnodes[3] = nodes[6];
+ tmpnodes[4] = nodes[1];
+ tmpnodes[5] = nodes[3];
+ tmpnodes[6] = nodes[5];
+ tmpnodes[7] = nodes[7];
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]));
+ aMesh->RemoveElement(f);
}
- myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
}
- break;
+ }
+ else { //////// polygon
+ vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
+ const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
+ if ( !f )
+ myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
+ else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+ {
+ // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
+ MESSAGE("ChangeElementNodes");
+ aMesh->ChangeElementNodes( f, nodes, nbn );
+ }
}
}
- }
+ while ( srcElements.Length() < myLastCreatedElems.Length() )
+ srcElements.Append( *srcEdge );
+
+ } // loop on free faces
+
// go to the next volume
iVol = 0;
while ( iVol++ < nbVolumesByStep ) v++;
}
} // sweep free links into faces
- // make a ceiling face with a normal external to a volume
+ // Make a ceiling face with a normal external to a volume
SMDS_VolumeTool lastVol( itElem->second.back() );
myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
break;
default:
- {
- if(itElem->second.back()->IsQuadratic()) {
- if(nbn==6) {
- if (!hasFreeLinks ||
- !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
- nodes[1], nodes[3], nodes[5]) ) {
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
- nodes[1], nodes[3], nodes[5])); break;
- }
- }
- else { // nbn==8
- if (!hasFreeLinks ||
- !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7]) )
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7]));
+ if(itElem->second.back()->IsQuadratic()) {
+ if(nbn==6) {
+ if (!hasFreeLinks ||
+ !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5]) ) {
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5]));
}
}
- else {
- int nbPolygonNodes = lastVol.NbFaceNodes( iF );
- vector<const SMDS_MeshNode*> polygon_nodes (nbPolygonNodes);
- for (int inode = 0; inode < nbPolygonNodes; inode++) {
- polygon_nodes[inode] = nodes[inode];
- }
- if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
- myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
+ else { // nbn==8
+ if (!hasFreeLinks ||
+ !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]) )
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]));
}
}
- break;
- }
+ else {
+ vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
+ if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
+ myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
+ }
+ } // switch
+
+ while ( srcElements.Length() < myLastCreatedElems.Length() )
+ srcElements.Append( myLastCreatedElems.Last() );
}
} // loop on swept elements
}
//purpose :
//=======================================================================
-void SMESH_MeshEditor::RotationSweep(map<int,const SMDS_MeshElement*> & theElems,
- const gp_Ax1& theAxis,
- const double theAngle,
- const int theNbSteps,
- const double theTol)
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
+ const gp_Ax1& theAxis,
+ const double theAngle,
+ const int theNbSteps,
+ const double theTol,
+ const bool theMakeGroups,
+ const bool theMakeWalls)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+
MESSAGE( "RotationSweep()");
gp_Trsf aTrsf;
aTrsf.SetRotation( theAxis, theAngle );
TElemOfElemListMap newElemsMap;
// loop on theElems
- map<int, const SMDS_MeshElement* >::iterator itElem;
+ TIDSortedElemSet::iterator itElem;
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- const SMDS_MeshElement* elem = (*itElem).second;
- if ( !elem )
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() == SMDSAbs_Volume )
continue;
vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
newNodesItVec.reserve( elem->NbNodes() );
// loop on elem nodes
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
while ( itN->more() ) {
-
// check if a node has been already sweeped
- const SMDS_MeshNode* node =
- static_cast<const SMDS_MeshNode*>( itN->next() );
+ const SMDS_MeshNode* node = cast2Node( itN->next() );
+
+ gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+ double coord[3];
+ aXYZ.Coord( coord[0], coord[1], coord[2] );
+ bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
+
TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
if ( nIt == mapNewNodes.end() ) {
nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
// make new nodes
- gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
- double coord[3];
- aXYZ.Coord( coord[0], coord[1], coord[2] );
- bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
+ //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+ //double coord[3];
+ //aXYZ.Coord( coord[0], coord[1], coord[2] );
+ //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
const SMDS_MeshNode * newNode = node;
for ( int i = 0; i < theNbSteps; i++ ) {
if ( !isOnAxis ) {
//aTrsf.Transforms( coord[0], coord[1], coord[2] );
newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
listNewNodes.push_back( newNode );
aTrsf2.Transforms( coord[0], coord[1], coord[2] );
//aTrsf.Transforms( coord[0], coord[1], coord[2] );
}
newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ }
+ else {
+ listNewNodes.push_back( newNode );
+ if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+ listNewNodes.push_back( newNode );
+ }
}
- listNewNodes.push_back( newNode );
}
}
- else {
+ /*
+ else {
// if current elem is quadratic and current node is not medium
// we have to check - may be it is needed to insert additional nodes
if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
- list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
- if(listNewNodes.size()==theNbSteps) {
- listNewNodes.clear();
- // make new nodes
- gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
- double coord[3];
- aXYZ.Coord( coord[0], coord[1], coord[2] );
- const SMDS_MeshNode * newNode = node;
- for(int i = 0; i<theNbSteps; i++) {
- aTrsf2.Transforms( coord[0], coord[1], coord[2] );
- newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
- myLastCreatedNodes.Append(newNode);
- listNewNodes.push_back( newNode );
- aTrsf2.Transforms( coord[0], coord[1], coord[2] );
- newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
- myLastCreatedNodes.Append(newNode);
- listNewNodes.push_back( newNode );
- }
- }
+ list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
+ if(listNewNodes.size()==theNbSteps) {
+ listNewNodes.clear();
+ // make new nodes
+ //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+ //double coord[3];
+ //aXYZ.Coord( coord[0], coord[1], coord[2] );
+ const SMDS_MeshNode * newNode = node;
+ if ( !isOnAxis ) {
+ for(int i = 0; i<theNbSteps; i++) {
+ aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ cout<<" 3 AddNode: "<<newNode;
+ myLastCreatedNodes.Append(newNode);
+ listNewNodes.push_back( newNode );
+ srcNodes.Append( node );
+ aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ cout<<" 4 AddNode: "<<newNode;
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
}
- }
+ }
+ else {
+ listNewNodes.push_back( newNode );
+ }
+ }
+ }
+ }
+ */
newNodesItVec.push_back( nIt );
}
// make new elements
- sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], theNbSteps, myLastCreatedElems );
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
}
- makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, myLastCreatedElems );
+ if ( theMakeWalls )
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
+ PGroupIDs newGroupIDs;
+ if ( theMakeGroups )
+ newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
+
+ return newGroupIDs;
}
//=======================================================================
//function : CreateNode
-//purpose :
+//purpose :
//=======================================================================
const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
const double y,
gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
if(P1.Distance(P2)<tolnode)
return aN;
- }
+ }
}
// create new node and return it
//purpose :
//=======================================================================
-void SMESH_MeshEditor::ExtrusionSweep
- (map<int,const SMDS_MeshElement*> & theElems,
- const gp_Vec& theStep,
- const int theNbSteps,
- TElemOfElemListMap& newElemsMap,
- const int theFlags,
- const double theTolerance)
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
+ const gp_Vec& theStep,
+ const int theNbSteps,
+ TElemOfElemListMap& newElemsMap,
+ const bool theMakeGroups,
+ const int theFlags,
+ const double theTolerance)
{
ExtrusParam aParams;
aParams.myDir = gp_Dir(theStep);
for(i=1; i<=theNbSteps; i++)
aParams.mySteps->Append(theStep.Magnitude());
- ExtrusionSweep(theElems,aParams,newElemsMap,theFlags,theTolerance);
-
+ return
+ ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
}
//purpose :
//=======================================================================
-void SMESH_MeshEditor::ExtrusionSweep
- (map<int,const SMDS_MeshElement*> & theElems,
- ExtrusParam& theParams,
- TElemOfElemListMap& newElemsMap,
- const int theFlags,
- const double theTolerance)
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
+ ExtrusParam& theParams,
+ TElemOfElemListMap& newElemsMap,
+ const bool theMakeGroups,
+ const int theFlags,
+ const double theTolerance)
{
+ MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+
SMESHDS_Mesh* aMesh = GetMeshDS();
int nbsteps = theParams.mySteps->Length();
//TElemOfVecOfMapNodesMap mapElemNewNodes;
// loop on theElems
- map<int, const SMDS_MeshElement* >::iterator itElem;
+ TIDSortedElemSet::iterator itElem;
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
// check element type
- const SMDS_MeshElement* elem = (*itElem).second;
- if ( !elem )
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() == SMDSAbs_Volume )
continue;
vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
// loop on elem nodes
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() ) {
-
+ while ( itN->more() )
+ {
// check if a node has been already sweeped
- const SMDS_MeshNode* node =
- static_cast<const SMDS_MeshNode*>( itN->next() );
+ const SMDS_MeshNode* node = cast2Node( itN->next() );
TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
//TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
if ( nIt == mapNewNodes.end() ) {
else {
const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
listNewNodes.push_back( newNode );
}
}
else {
const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
listNewNodes.push_back( newNode );
//vecNewNodes[i]=newNode;
}
else {
const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
listNewNodes.push_back( newNode );
}
coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
else {
const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
listNewNodes.push_back( newNode );
}
}
newNodesItVec.push_back( nIt );
}
// make new elements
- sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], nbsteps, myLastCreatedElems );
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
}
if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
- makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, myLastCreatedElems );
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
}
-}
+ PGroupIDs newGroupIDs;
+ if ( theMakeGroups )
+ newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
+ return newGroupIDs;
+}
+/*
//=======================================================================
//class : SMESH_MeshEditor_PathPoint
//purpose : auxiliary class
//=======================================================================
class SMESH_MeshEditor_PathPoint {
public:
- SMESH_MeshEditor_PathPoint() {
- myPnt.SetCoord(99., 99., 99.);
- myTgt.SetCoord(1.,0.,0.);
- myAngle=0.;
- myPrm=0.;
- }
- void SetPnt(const gp_Pnt& aP3D){
- myPnt=aP3D;
- }
- void SetTangent(const gp_Dir& aTgt){
- myTgt=aTgt;
- }
- void SetAngle(const double& aBeta){
- myAngle=aBeta;
- }
- void SetParameter(const double& aPrm){
- myPrm=aPrm;
- }
- const gp_Pnt& Pnt()const{
- return myPnt;
- }
- const gp_Dir& Tangent()const{
- return myTgt;
- }
- double Angle()const{
- return myAngle;
- }
- double Parameter()const{
- return myPrm;
- }
+SMESH_MeshEditor_PathPoint() {
+myPnt.SetCoord(99., 99., 99.);
+myTgt.SetCoord(1.,0.,0.);
+myAngle=0.;
+myPrm=0.;
+}
+void SetPnt(const gp_Pnt& aP3D){
+myPnt=aP3D;
+}
+void SetTangent(const gp_Dir& aTgt){
+myTgt=aTgt;
+}
+void SetAngle(const double& aBeta){
+myAngle=aBeta;
+}
+void SetParameter(const double& aPrm){
+myPrm=aPrm;
+}
+const gp_Pnt& Pnt()const{
+return myPnt;
+}
+const gp_Dir& Tangent()const{
+return myTgt;
+}
+double Angle()const{
+return myAngle;
+}
+double Parameter()const{
+return myPrm;
+}
protected:
- gp_Pnt myPnt;
- gp_Dir myTgt;
- double myAngle;
- double myPrm;
+gp_Pnt myPnt;
+gp_Dir myTgt;
+double myAngle;
+double myPrm;
};
+*/
//=======================================================================
//function : ExtrusionAlongTrack
//purpose :
//=======================================================================
SMESH_MeshEditor::Extrusion_Error
- SMESH_MeshEditor::ExtrusionAlongTrack (std::map<int,const SMDS_MeshElement*> & theElements,
- SMESH_subMesh* theTrack,
- const SMDS_MeshNode* theN1,
- const bool theHasAngles,
- std::list<double>& theAngles,
- const bool theHasRefPoint,
- const gp_Pnt& theRefPoint)
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
+ SMESH_subMesh* theTrack,
+ const SMDS_MeshNode* theN1,
+ const bool theHasAngles,
+ list<double>& theAngles,
+ const bool theLinearVariation,
+ const bool theHasRefPoint,
+ const gp_Pnt& theRefPoint,
+ const bool theMakeGroups)
{
+ MESSAGE("ExtrusionAlongTrack");
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- MESSAGE("SMESH_MeshEditor::ExtrusionAlongTrack")
- int j, aNbTP, aNbE, aNb;
- double aT1, aT2, aT, aAngle, aX, aY, aZ;
+ int aNbE;
std::list<double> aPrms;
- std::list<double>::iterator aItD;
- std::map<int, const SMDS_MeshElement* >::iterator itElem;
+ TIDSortedElemSet::iterator itElem;
- Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
- gp_Pnt aP3D, aV0;
- gp_Vec aVec;
gp_XYZ aGC;
- Handle(Geom_Curve) aC3D;
TopoDS_Edge aTrackEdge;
TopoDS_Vertex aV1, aV2;
SMDSAbs_ElementType aTypeE;
TNodeOfNodeListMap mapNewNodes;
- TElemOfVecOfNnlmiMap mapElemNewNodes;
- TElemOfElemListMap newElemsMap;
-
- aTolVec=1.e-7;
- aTolVec2=aTolVec*aTolVec;
// 1. Check data
aNbE = theElements.size();
// 1.1 Track Pattern
ASSERT( theTrack );
- SMESHDS_SubMesh* pSubMeshDS=theTrack->GetSubMeshDS();
+ SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
aItE = pSubMeshDS->GetElements();
while ( aItE->more() ) {
return EXTR_PATH_NOT_EDGE;
}
+ list<SMESH_MeshEditor_PathPoint> fullList;
+
const TopoDS_Shape& aS = theTrack->GetSubShape();
- // Sub shape for the Pattern must be an Edge
- if ( aS.ShapeType() != TopAbs_EDGE )
+ // Sub shape for the Pattern must be an Edge or Wire
+ if( aS.ShapeType() == TopAbs_EDGE ) {
+ aTrackEdge = TopoDS::Edge( aS );
+ // the Edge must not be degenerated
+ if ( BRep_Tool::Degenerated( aTrackEdge ) )
+ return EXTR_BAD_PATH_SHAPE;
+ TopExp::Vertices( aTrackEdge, aV1, aV2 );
+ aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN1 = aItN->next();
+ aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN2 = aItN->next();
+ // starting node must be aN1 or aN2
+ if ( !( aN1 == theN1 || aN2 == theN1 ) )
+ return EXTR_BAD_STARTING_NODE;
+ aItN = pSubMeshDS->GetNodes();
+ while ( aItN->more() ) {
+ const SMDS_MeshNode* pNode = aItN->next();
+ const SMDS_EdgePosition* pEPos =
+ static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
+ double aT = pEPos->GetUParameter();
+ aPrms.push_back( aT );
+ }
+ //Extrusion_Error err =
+ MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+ }
+ else if( aS.ShapeType() == TopAbs_WIRE ) {
+ list< SMESH_subMesh* > LSM;
+ TopTools_SequenceOfShape Edges;
+ SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
+ while(itSM->more()) {
+ SMESH_subMesh* SM = itSM->next();
+ LSM.push_back(SM);
+ const TopoDS_Shape& aS = SM->GetSubShape();
+ Edges.Append(aS);
+ }
+ list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
+ int startNid = theN1->GetID();
+ TColStd_MapOfInteger UsedNums;
+ int NbEdges = Edges.Length();
+ int i = 1;
+ for(; i<=NbEdges; i++) {
+ int k = 0;
+ list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
+ for(; itLSM!=LSM.end(); itLSM++) {
+ k++;
+ if(UsedNums.Contains(k)) continue;
+ aTrackEdge = TopoDS::Edge( Edges.Value(k) );
+ SMESH_subMesh* locTrack = *itLSM;
+ SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
+ TopExp::Vertices( aTrackEdge, aV1, aV2 );
+ aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN1 = aItN->next();
+ aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN2 = aItN->next();
+ // starting node must be aN1 or aN2
+ if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+ // 2. Collect parameters on the track edge
+ aPrms.clear();
+ aItN = locMeshDS->GetNodes();
+ while ( aItN->more() ) {
+ const SMDS_MeshNode* pNode = aItN->next();
+ const SMDS_EdgePosition* pEPos =
+ static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
+ double aT = pEPos->GetUParameter();
+ aPrms.push_back( aT );
+ }
+ list<SMESH_MeshEditor_PathPoint> LPP;
+ //Extrusion_Error err =
+ MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+ LLPPs.push_back(LPP);
+ UsedNums.Add(k);
+ // update startN for search following egde
+ if( aN1->GetID() == startNid ) startNid = aN2->GetID();
+ else startNid = aN1->GetID();
+ break;
+ }
+ }
+ list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
+ list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
+ list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
+ for(; itPP!=firstList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+ SMESH_MeshEditor_PathPoint PP1 = fullList.back();
+ fullList.pop_back();
+ itLLPP++;
+ for(; itLLPP!=LLPPs.end(); itLLPP++) {
+ list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
+ itPP = currList.begin();
+ SMESH_MeshEditor_PathPoint PP2 = currList.front();
+ gp_Dir D1 = PP1.Tangent();
+ gp_Dir D2 = PP2.Tangent();
+ gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
+ (D1.Z()+D2.Z())/2 ) );
+ PP1.SetTangent(Dnew);
+ fullList.push_back(PP1);
+ itPP++;
+ for(; itPP!=firstList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+ PP1 = fullList.back();
+ fullList.pop_back();
+ }
+ // if wire not closed
+ fullList.push_back(PP1);
+ // else ???
+ }
+ else {
return EXTR_BAD_PATH_SHAPE;
+ }
- aTrackEdge = TopoDS::Edge( aS );
- // the Edge must not be degenerated
- if ( BRep_Tool::Degenerated( aTrackEdge ) )
- return EXTR_BAD_PATH_SHAPE;
+ return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+ theHasRefPoint, theRefPoint, theMakeGroups);
+}
- TopExp::Vertices( aTrackEdge, aV1, aV2 );
- aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
- aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
- aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN1 = aItN->next();
+//=======================================================================
+//function : ExtrusionAlongTrack
+//purpose :
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
+ SMESH_Mesh* theTrack,
+ const SMDS_MeshNode* theN1,
+ const bool theHasAngles,
+ list<double>& theAngles,
+ const bool theLinearVariation,
+ const bool theHasRefPoint,
+ const gp_Pnt& theRefPoint,
+ const bool theMakeGroups)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
- aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN2 = aItN->next();
+ int aNbE;
+ std::list<double> aPrms;
+ TIDSortedElemSet::iterator itElem;
- // starting node must be aN1 or aN2
- if ( !( aN1 == theN1 || aN2 == theN1 ) )
- return EXTR_BAD_STARTING_NODE;
+ gp_XYZ aGC;
+ TopoDS_Edge aTrackEdge;
+ TopoDS_Vertex aV1, aV2;
- aNbTP = pSubMeshDS->NbNodes() + 2;
+ SMDS_ElemIteratorPtr aItE;
+ SMDS_NodeIteratorPtr aItN;
+ SMDSAbs_ElementType aTypeE;
- // 1.2. Angles
- vector<double> aAngles( aNbTP );
+ TNodeOfNodeListMap mapNewNodes;
- for ( j=0; j < aNbTP; ++j ) {
- aAngles[j] = 0.;
- }
+ // 1. Check data
+ aNbE = theElements.size();
+ // nothing to do
+ if ( !aNbE )
+ return EXTR_NO_ELEMENTS;
- if ( theHasAngles ) {
- aItD = theAngles.begin();
- for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
- aAngle = *aItD;
- aAngles[j] = aAngle;
+ // 1.1 Track Pattern
+ ASSERT( theTrack );
+
+ SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
+
+ aItE = pMeshDS->elementsIterator();
+ while ( aItE->more() ) {
+ const SMDS_MeshElement* pE = aItE->next();
+ aTypeE = pE->GetType();
+ // Pattern must contain links only
+ if ( aTypeE != SMDSAbs_Edge )
+ return EXTR_PATH_NOT_EDGE;
+ }
+
+ list<SMESH_MeshEditor_PathPoint> fullList;
+
+ const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
+ // Sub shape for the Pattern must be an Edge or Wire
+ if( aS.ShapeType() == TopAbs_EDGE ) {
+ aTrackEdge = TopoDS::Edge( aS );
+ // the Edge must not be degenerated
+ if ( BRep_Tool::Degenerated( aTrackEdge ) )
+ return EXTR_BAD_PATH_SHAPE;
+ TopExp::Vertices( aTrackEdge, aV1, aV2 );
+ aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN1 = aItN->next();
+ aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN2 = aItN->next();
+ // starting node must be aN1 or aN2
+ if ( !( aN1 == theN1 || aN2 == theN1 ) )
+ return EXTR_BAD_STARTING_NODE;
+ aItN = pMeshDS->nodesIterator();
+ while ( aItN->more() ) {
+ const SMDS_MeshNode* pNode = aItN->next();
+ if( pNode==aN1 || pNode==aN2 ) continue;
+ const SMDS_EdgePosition* pEPos =
+ static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
+ double aT = pEPos->GetUParameter();
+ aPrms.push_back( aT );
+ }
+ //Extrusion_Error err =
+ MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+ }
+ else if( aS.ShapeType() == TopAbs_WIRE ) {
+ list< SMESH_subMesh* > LSM;
+ TopTools_SequenceOfShape Edges;
+ TopExp_Explorer eExp(aS, TopAbs_EDGE);
+ for(; eExp.More(); eExp.Next()) {
+ TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
+ if( BRep_Tool::Degenerated(E) ) continue;
+ SMESH_subMesh* SM = theTrack->GetSubMesh(E);
+ if(SM) {
+ LSM.push_back(SM);
+ Edges.Append(E);
+ }
+ }
+ list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
+ int startNid = theN1->GetID();
+ TColStd_MapOfInteger UsedNums;
+ int NbEdges = Edges.Length();
+ int i = 1;
+ for(; i<=NbEdges; i++) {
+ int k = 0;
+ list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
+ for(; itLSM!=LSM.end(); itLSM++) {
+ k++;
+ if(UsedNums.Contains(k)) continue;
+ aTrackEdge = TopoDS::Edge( Edges.Value(k) );
+ SMESH_subMesh* locTrack = *itLSM;
+ SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
+ TopExp::Vertices( aTrackEdge, aV1, aV2 );
+ aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN1 = aItN->next();
+ aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN2 = aItN->next();
+ // starting node must be aN1 or aN2
+ if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+ // 2. Collect parameters on the track edge
+ aPrms.clear();
+ aItN = locMeshDS->GetNodes();
+ while ( aItN->more() ) {
+ const SMDS_MeshNode* pNode = aItN->next();
+ const SMDS_EdgePosition* pEPos =
+ static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
+ double aT = pEPos->GetUParameter();
+ aPrms.push_back( aT );
+ }
+ list<SMESH_MeshEditor_PathPoint> LPP;
+ //Extrusion_Error err =
+ MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+ LLPPs.push_back(LPP);
+ UsedNums.Add(k);
+ // update startN for search following egde
+ if( aN1->GetID() == startNid ) startNid = aN2->GetID();
+ else startNid = aN1->GetID();
+ break;
+ }
+ }
+ list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
+ list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
+ list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
+ for(; itPP!=firstList.end(); itPP++) {
+ fullList.push_back( *itPP );
}
+ SMESH_MeshEditor_PathPoint PP1 = fullList.back();
+ fullList.pop_back();
+ itLLPP++;
+ for(; itLLPP!=LLPPs.end(); itLLPP++) {
+ list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
+ itPP = currList.begin();
+ SMESH_MeshEditor_PathPoint PP2 = currList.front();
+ gp_Pnt P1 = PP1.Pnt();
+ //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
+ gp_Pnt P2 = PP2.Pnt();
+ gp_Dir D1 = PP1.Tangent();
+ gp_Dir D2 = PP2.Tangent();
+ gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
+ (D1.Z()+D2.Z())/2 ) );
+ PP1.SetTangent(Dnew);
+ fullList.push_back(PP1);
+ itPP++;
+ for(; itPP!=currList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+ PP1 = fullList.back();
+ fullList.pop_back();
+ }
+ // if wire not closed
+ fullList.push_back(PP1);
+ // else ???
+ }
+ else {
+ return EXTR_BAD_PATH_SHAPE;
}
- // 2. Collect parameters on the track edge
- aPrms.push_back( aT1 );
- aPrms.push_back( aT2 );
+ return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+ theHasRefPoint, theRefPoint, theMakeGroups);
+}
- aItN = pSubMeshDS->GetNodes();
- while ( aItN->more() ) {
- const SMDS_MeshNode* pNode = aItN->next();
- const SMDS_EdgePosition* pEPos =
- static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
- aT = pEPos->GetUParameter();
- aPrms.push_back( aT );
- }
+//=======================================================================
+//function : MakeEdgePathPoints
+//purpose : auxilary for ExtrusionAlongTrack
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
+ const TopoDS_Edge& aTrackEdge,
+ bool FirstIsStart,
+ list<SMESH_MeshEditor_PathPoint>& LPP)
+{
+ Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
+ aTolVec=1.e-7;
+ aTolVec2=aTolVec*aTolVec;
+ double aT1, aT2;
+ TopoDS_Vertex aV1, aV2;
+ TopExp::Vertices( aTrackEdge, aV1, aV2 );
+ aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
+ aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
+ // 2. Collect parameters on the track edge
+ aPrms.push_front( aT1 );
+ aPrms.push_back( aT2 );
// sort parameters
aPrms.sort();
- if ( aN1 == theN1 ) {
+ if( FirstIsStart ) {
if ( aT1 > aT2 ) {
aPrms.reverse();
}
aPrms.reverse();
}
}
-
// 3. Path Points
SMESH_MeshEditor_PathPoint aPP;
- vector<SMESH_MeshEditor_PathPoint> aPPs( aNbTP );
- //
- aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
- //
- aItD = aPrms.begin();
- for ( j=0; aItD != aPrms.end(); ++aItD, ++j ) {
- aT = *aItD;
+ Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
+ std::list<double>::iterator aItD = aPrms.begin();
+ for(; aItD != aPrms.end(); ++aItD) {
+ double aT = *aItD;
+ gp_Pnt aP3D;
+ gp_Vec aVec;
aC3D->D1( aT, aP3D, aVec );
aL2 = aVec.SquareMagnitude();
if ( aL2 < aTolVec2 )
return EXTR_CANT_GET_TANGENT;
-
gp_Dir aTgt( aVec );
- aAngle = aAngles[j];
-
aPP.SetPnt( aP3D );
aPP.SetTangent( aTgt );
- aPP.SetAngle( aAngle );
aPP.SetParameter( aT );
- aPPs[j]=aPP;
+ LPP.push_back(aPP);
+ }
+ return EXTR_OK;
+}
+
+
+//=======================================================================
+//function : MakeExtrElements
+//purpose : auxilary for ExtrusionAlongTrack
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
+ list<SMESH_MeshEditor_PathPoint>& fullList,
+ const bool theHasAngles,
+ list<double>& theAngles,
+ const bool theLinearVariation,
+ const bool theHasRefPoint,
+ const gp_Pnt& theRefPoint,
+ const bool theMakeGroups)
+{
+ MESSAGE("MakeExtrElements");
+ //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
+ int aNbTP = fullList.size();
+ vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
+ // Angles
+ if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
+ LinearAngleVariation(aNbTP-1, theAngles);
+ }
+ vector<double> aAngles( aNbTP );
+ int j = 0;
+ for(; j<aNbTP; ++j) {
+ aAngles[j] = 0.;
+ }
+ if ( theHasAngles ) {
+ double anAngle;;
+ std::list<double>::iterator aItD = theAngles.begin();
+ for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
+ anAngle = *aItD;
+ aAngles[j] = anAngle;
+ }
}
+ // fill vector of path points with angles
+ //aPPs.resize(fullList.size());
+ j = -1;
+ list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
+ for(; itPP!=fullList.end(); itPP++) {
+ j++;
+ SMESH_MeshEditor_PathPoint PP = *itPP;
+ PP.SetAngle(aAngles[j]);
+ aPPs[j] = PP;
+ }
+
+ TNodeOfNodeListMap mapNewNodes;
+ TElemOfVecOfNnlmiMap mapElemNewNodes;
+ TElemOfElemListMap newElemsMap;
+ TIDSortedElemSet::iterator itElem;
+ double aX, aY, aZ;
+ int aNb;
+ SMDSAbs_ElementType aTypeE;
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
// 3. Center of rotation aV0
- aV0 = theRefPoint;
+ gp_Pnt aV0 = theRefPoint;
+ gp_XYZ aGC;
if ( !theHasRefPoint ) {
aNb = 0;
aGC.SetCoord( 0.,0.,0. );
itElem = theElements.begin();
for ( ; itElem != theElements.end(); itElem++ ) {
- const SMDS_MeshElement* elem = (*itElem).second;
+ const SMDS_MeshElement* elem = *itElem;
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
while ( itN->more() ) {
- const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
- aX = node->X();
- aY = node->Y();
- aZ = node->Z();
-
- if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
- list<const SMDS_MeshNode*> aLNx;
- mapNewNodes[node] = aLNx;
- //
- gp_XYZ aXYZ( aX, aY, aZ );
- aGC += aXYZ;
- ++aNb;
- }
+ const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
+ aX = node->X();
+ aY = node->Y();
+ aZ = node->Z();
+
+ if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
+ list<const SMDS_MeshNode*> aLNx;
+ mapNewNodes[node] = aLNx;
+ //
+ gp_XYZ aXYZ( aX, aY, aZ );
+ aGC += aXYZ;
+ ++aNb;
+ }
}
}
aGC /= aNb;
for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
// check element type
- const SMDS_MeshElement* elem = (*itElem).second;
+ const SMDS_MeshElement* elem = *itElem;
aTypeE = elem->GetType();
if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
continue;
newNodesItVec.reserve( elem->NbNodes() );
// loop on elem nodes
+ int nodeIndex = -1;
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() ) {
-
+ while ( itN->more() )
+ {
+ ++nodeIndex;
// check if a node has been already processed
const SMDS_MeshNode* node =
- static_cast<const SMDS_MeshNode*>( itN->next() );
+ static_cast<const SMDS_MeshNode*>( itN->next() );
TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
if ( nIt == mapNewNodes.end() ) {
nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
- // make new nodes
- aX = node->X(); aY = node->Y(); aZ = node->Z();
-
- Standard_Real aAngle1x, aAngleT1T0, aTolAng;
- gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
- gp_Ax1 anAx1, anAxT1T0;
- gp_Dir aDT1x, aDT0x, aDT1T0;
-
- aTolAng=1.e-4;
-
- aV0x = aV0;
- aPN0.SetCoord(aX, aY, aZ);
-
- const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
- aP0x = aPP0.Pnt();
- aDT0x= aPP0.Tangent();
-
- for ( j = 1; j < aNbTP; ++j ) {
- const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
- aP1x = aPP1.Pnt();
- aDT1x = aPP1.Tangent();
- aAngle1x = aPP1.Angle();
-
- gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
- // Translation
- gp_Vec aV01x( aP0x, aP1x );
- aTrsf.SetTranslation( aV01x );
-
- // traslated point
- aV1x = aV0x.Transformed( aTrsf );
- aPN1 = aPN0.Transformed( aTrsf );
-
- // rotation 1 [ T1,T0 ]
- aAngleT1T0=-aDT1x.Angle( aDT0x );
- if (fabs(aAngleT1T0) > aTolAng) {
- aDT1T0=aDT1x^aDT0x;
- anAxT1T0.SetLocation( aV1x );
- anAxT1T0.SetDirection( aDT1T0 );
- aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
-
- aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
- }
+ // make new nodes
+ aX = node->X(); aY = node->Y(); aZ = node->Z();
+
+ Standard_Real aAngle1x, aAngleT1T0, aTolAng;
+ gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
+ gp_Ax1 anAx1, anAxT1T0;
+ gp_Dir aDT1x, aDT0x, aDT1T0;
+
+ aTolAng=1.e-4;
+
+ aV0x = aV0;
+ aPN0.SetCoord(aX, aY, aZ);
+
+ const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
+ aP0x = aPP0.Pnt();
+ aDT0x= aPP0.Tangent();
+ //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
+
+ for ( j = 1; j < aNbTP; ++j ) {
+ const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
+ aP1x = aPP1.Pnt();
+ aDT1x = aPP1.Tangent();
+ aAngle1x = aPP1.Angle();
+
+ gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
+ // Translation
+ gp_Vec aV01x( aP0x, aP1x );
+ aTrsf.SetTranslation( aV01x );
+
+ // traslated point
+ aV1x = aV0x.Transformed( aTrsf );
+ aPN1 = aPN0.Transformed( aTrsf );
+
+ // rotation 1 [ T1,T0 ]
+ aAngleT1T0=-aDT1x.Angle( aDT0x );
+ if (fabs(aAngleT1T0) > aTolAng) {
+ aDT1T0=aDT1x^aDT0x;
+ anAxT1T0.SetLocation( aV1x );
+ anAxT1T0.SetDirection( aDT1T0 );
+ aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
+
+ aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
+ }
- // rotation 2
- if ( theHasAngles ) {
- anAx1.SetLocation( aV1x );
- anAx1.SetDirection( aDT1x );
- aTrsfRot.SetRotation( anAx1, aAngle1x );
+ // rotation 2
+ if ( theHasAngles ) {
+ anAx1.SetLocation( aV1x );
+ anAx1.SetDirection( aDT1x );
+ aTrsfRot.SetRotation( anAx1, aAngle1x );
- aPN1 = aPN1.Transformed( aTrsfRot );
- }
+ aPN1 = aPN1.Transformed( aTrsfRot );
+ }
- // make new node
+ // make new node
+ //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
// create additional node
double x = ( aPN1.X() + aPN0.X() )/2.;
double z = ( aPN1.Z() + aPN0.Z() )/2.;
const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
listNewNodes.push_back( newNode );
}
- aX = aPN1.X();
- aY = aPN1.Y();
- aZ = aPN1.Z();
- const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
+ aX = aPN1.X();
+ aY = aPN1.Y();
+ aZ = aPN1.Z();
+ const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
myLastCreatedNodes.Append(newNode);
- listNewNodes.push_back( newNode );
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
- aPN0 = aPN1;
- aP0x = aP1x;
- aV0x = aV1x;
- aDT0x = aDT1x;
- }
+ aPN0 = aPN1;
+ aP0x = aP1x;
+ aV0x = aV1x;
+ aDT0x = aDT1x;
+ }
}
else {
double y = ( N->Y() + P.Y() )/2.;
double z = ( N->Z() + P.Z() )/2.;
const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
+ srcNodes.Append( node );
myLastCreatedNodes.Append(newN);
aNodes[2*i] = newN;
aNodes[2*i+1] = N;
// make new elements
//sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
// newNodesItVec[0]->second.size(), myLastCreatedElems );
- sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
- aNbTP-1, myLastCreatedElems );
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
}
- makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElements,
- aNbTP-1, myLastCreatedElems );
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
+
+ if ( theMakeGroups )
+ generateGroups( srcNodes, srcElems, "extruded");
return EXTR_OK;
}
+
//=======================================================================
-//function : Transform
-//purpose :
+//function : LinearAngleVariation
+//purpose : auxilary for ExtrusionAlongTrack
//=======================================================================
+void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
+ list<double>& Angles)
+{
+ int nbAngles = Angles.size();
+ if( nbSteps > nbAngles ) {
+ vector<double> theAngles(nbAngles);
+ list<double>::iterator it = Angles.begin();
+ int i = -1;
+ for(; it!=Angles.end(); it++) {
+ i++;
+ theAngles[i] = (*it);
+ }
+ list<double> res;
+ double rAn2St = double( nbAngles ) / double( nbSteps );
+ double angPrev = 0, angle;
+ for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
+ double angCur = rAn2St * ( iSt+1 );
+ double angCurFloor = floor( angCur );
+ double angPrevFloor = floor( angPrev );
+ if ( angPrevFloor == angCurFloor )
+ angle = rAn2St * theAngles[ int( angCurFloor ) ];
+ else {
+ int iP = int( angPrevFloor );
+ double angPrevCeil = ceil(angPrev);
+ angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
+
+ int iC = int( angCurFloor );
+ if ( iC < nbAngles )
+ angle += ( angCur - angCurFloor ) * theAngles[ iC ];
+
+ iP = int( angPrevCeil );
+ while ( iC-- > iP )
+ angle += theAngles[ iC ];
+ }
+ res.push_back(angle);
+ angPrev = angCur;
+ }
+ Angles.clear();
+ it = res.begin();
+ for(; it!=res.end(); it++)
+ Angles.push_back( *it );
+ }
+}
+
-void SMESH_MeshEditor::Transform (map<int,const SMDS_MeshElement*> & theElems,
- const gp_Trsf& theTrsf,
- const bool theCopy)
+//================================================================================
+/*!
+ * \brief Move or copy theElements applying theTrsf to their nodes
+ * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
+ * \param theTrsf - transformation to apply
+ * \param theCopy - if true, create translated copies of theElems
+ * \param theMakeGroups - if true and theCopy, create translated groups
+ * \param theTargetMesh - mesh to copy translated elements into
+ * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
+ */
+//================================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
+ const gp_Trsf& theTrsf,
+ const bool theCopy,
+ const bool theMakeGroups,
+ SMESH_Mesh* theTargetMesh)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- bool needReverse;
+ bool needReverse = false;
+ string groupPostfix;
switch ( theTrsf.Form() ) {
case gp_PntMirror:
+ MESSAGE("gp_PntMirror");
+ needReverse = true;
+ groupPostfix = "mirrored";
+ break;
+ case gp_Ax1Mirror:
+ MESSAGE("gp_Ax1Mirror");
+ groupPostfix = "mirrored";
+ break;
case gp_Ax2Mirror:
+ MESSAGE("gp_Ax2Mirror");
needReverse = true;
+ groupPostfix = "mirrored";
+ break;
+ case gp_Rotation:
+ MESSAGE("gp_Rotation");
+ groupPostfix = "rotated";
+ break;
+ case gp_Translation:
+ MESSAGE("gp_Translation");
+ groupPostfix = "translated";
+ break;
+ case gp_Scale:
+ MESSAGE("gp_Scale");
+ groupPostfix = "scaled";
+ break;
+ case gp_CompoundTrsf: // different scale by axis
+ MESSAGE("gp_CompoundTrsf");
+ groupPostfix = "scaled";
break;
default:
+ MESSAGE("default");
needReverse = false;
+ groupPostfix = "transformed";
}
- SMESHDS_Mesh* aMesh = GetMeshDS();
+ SMESH_MeshEditor targetMeshEditor( theTargetMesh );
+ SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
// map old node to new one
TNodeNodeMap nodeMap;
// elements sharing moved nodes; those of them which have all
// nodes mirrored but are not in theElems are to be reversed
- map<int,const SMDS_MeshElement*> inverseElemSet;
+ TIDSortedElemSet inverseElemSet;
- // loop on theElems
- map<int, const SMDS_MeshElement* >::iterator itElem;
- for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- const SMDS_MeshElement* elem = (*itElem).second;
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+
+ // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
+ TIDSortedElemSet orphanNode;
+
+ if ( theElems.empty() ) // transform the whole mesh
+ {
+ // add all elements
+ SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
+ while ( eIt->more() ) theElems.insert( eIt->next() );
+ // add orphan nodes
+ SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
+ while ( nIt->more() )
+ {
+ const SMDS_MeshNode* node = nIt->next();
+ if ( node->NbInverseElements() == 0)
+ orphanNode.insert( node );
+ }
+ }
+
+ // loop on elements to transform nodes : first orphan nodes then elems
+ TIDSortedElemSet::iterator itElem;
+ TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
+ for (int i=0; i<2; i++)
+ for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
+ const SMDS_MeshElement* elem = *itElem;
if ( !elem )
continue;
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
while ( itN->more() ) {
+ const SMDS_MeshNode* node = cast2Node( itN->next() );
// check if a node has been already transformed
- const SMDS_MeshNode* node =
- static_cast<const SMDS_MeshNode*>( itN->next() );
- if (nodeMap.find( node ) != nodeMap.end() )
+ pair<TNodeNodeMap::iterator,bool> n2n_isnew =
+ nodeMap.insert( make_pair ( node, node ));
+ if ( !n2n_isnew.second )
continue;
double coord[3];
coord[1] = node->Y();
coord[2] = node->Z();
theTrsf.Transforms( coord[0], coord[1], coord[2] );
- const SMDS_MeshNode * newNode = node;
- if ( theCopy ) {
- newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ if ( theTargetMesh ) {
+ const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
+ n2n_isnew.first->second = newNode;
myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ }
+ else if ( theCopy ) {
+ const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ n2n_isnew.first->second = newNode;
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
}
else {
aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
const_cast< SMDS_MeshNode* > ( node )->SetPosition
( SMDS_SpacePosition::originSpacePosition() );
}
- nodeMap.insert( TNodeNodeMap::value_type( node, newNode ));
// keep inverse elements
- if ( !theCopy && needReverse ) {
+ if ( !theCopy && !theTargetMesh && needReverse ) {
SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
while ( invElemIt->more() ) {
- const SMDS_MeshElement* iel = invElemIt->next();
- inverseElemSet.insert( make_pair(iel->GetID(),iel) );
+ const SMDS_MeshElement* iel = invElemIt->next();
+ inverseElemSet.insert( iel );
}
}
}
}
- // either new elements are to be created
- // or a mirrored element are to be reversed
- if ( !theCopy && !needReverse)
- return;
+ // either create new elements or reverse mirrored ones
+ if ( !theCopy && !needReverse && !theTargetMesh )
+ return PGroupIDs();
- if ( !inverseElemSet.empty()) {
- map<int,const SMDS_MeshElement*>::iterator invElemIt = inverseElemSet.begin();
- for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
- theElems.insert( *invElemIt );
- }
+ TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
+ for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
+ theElems.insert( *invElemIt );
// replicate or reverse elements
-
+ // TODO revoir ordre reverse vtk
enum {
REV_TETRA = 0, // = nbNodes - 4
REV_PYRAMID = 1, // = nbNodes - 4
REV_FACE = 3,
REV_HEXA = 4, // = nbNodes - 4
FORWARD = 5
- };
+ };
int index[][8] = {
{ 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
{ 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
{ 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
};
- for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- const SMDS_MeshElement* elem = (*itElem).second;
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+ {
+ const SMDS_MeshElement* elem = *itElem;
if ( !elem || elem->GetType() == SMDSAbs_Node )
continue;
if ( iNode != nbNodes )
continue; // not all nodes transformed
- if ( theCopy ) {
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
+ srcElems.Append( elem );
+ }
+ else if ( theCopy ) {
myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
+ srcElems.Append( elem );
}
else {
aMesh->ChangePolygonNodes(elem, poly_nodes);
case SMDSAbs_Volume:
{
// ATTENTION: Reversing is not yet done!!!
- const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
- (const SMDS_PolyhedralVolumeOfNodes*) elem;
+ const SMDS_VtkVolume* aPolyedre =
+ dynamic_cast<const SMDS_VtkVolume*>( elem );
if (!aPolyedre) {
MESSAGE("Warning: bad volumic element");
continue;
if ( !allTransformed )
continue; // not all nodes transformed
- if ( theCopy ) {
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
+ srcElems.Append( elem );
+ }
+ else if ( theCopy ) {
myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
+ srcElems.Append( elem );
}
else {
aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
// Regular elements
int* i = index[ FORWARD ];
- if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
+ if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
if ( elemType == SMDSAbs_Face )
i = index[ REV_FACE ];
else
i = index[ nbNodes - 4 ];
-
+ }
if(elem->IsQuadratic()) {
static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
i = anIds;
}
// find transformed nodes
- const SMDS_MeshNode* nodes[8];
+ vector<const SMDS_MeshNode*> nodes(nbNodes);
int iNode = 0;
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
while ( itN->more() ) {
if ( iNode != nbNodes )
continue; // not all nodes transformed
- if ( theCopy ) {
- // add a new element
- switch ( elemType ) {
- case SMDSAbs_Edge:
- if ( nbNodes == 2 )
- myLastCreatedElems.Append(aMesh->AddEdge( nodes[ 0 ], nodes[ 1 ] ));
- else
- myLastCreatedElems.Append(aMesh->AddEdge( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
- break;
- case SMDSAbs_Face:
- if ( nbNodes == 3 )
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
- else if(nbNodes==4)
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ]));
- else if(nbNodes==6)
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
- nodes[4], nodes[5]));
- else // nbNodes==8
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
- nodes[4], nodes[5], nodes[6], nodes[7]));
- break;
- case SMDSAbs_Volume:
- if ( nbNodes == 4 )
- myLastCreatedElems.Append(aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ] ));
- else if ( nbNodes == 8 )
- myLastCreatedElems.Append(aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
- nodes[ 4 ], nodes[ 5 ], nodes[ 6 ] , nodes[ 7 ]));
- else if ( nbNodes == 6 )
- myLastCreatedElems.Append(aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
- nodes[ 4 ], nodes[ 5 ]));
- else if ( nbNodes == 5 )
- myLastCreatedElems.Append(aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
- nodes[ 4 ]));
- else if(nbNodes==10)
- myLastCreatedElems.Append(aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4],
- nodes[5], nodes[6], nodes[7], nodes[8], nodes[9]));
- else if(nbNodes==13)
- myLastCreatedElems.Append(aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4],
- nodes[5], nodes[6], nodes[7], nodes[8], nodes[9],
- nodes[10], nodes[11], nodes[12]));
- else if(nbNodes==15)
- myLastCreatedElems.Append(aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4],
- nodes[5], nodes[6], nodes[7], nodes[8], nodes[9],
- nodes[10], nodes[11], nodes[12], nodes[13], nodes[14]));
- else // nbNodes==20
- myLastCreatedElems.Append(aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4],
- nodes[5], nodes[6], nodes[7], nodes[8], nodes[9],
- nodes[10], nodes[11], nodes[12], nodes[13], nodes[14],
- nodes[15], nodes[16], nodes[17], nodes[18], nodes[19]));
- break;
- default:;
+ if ( theTargetMesh ) {
+ if ( SMDS_MeshElement* copy =
+ targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+ myLastCreatedElems.Append( copy );
+ srcElems.Append( elem );
}
}
- else
- {
+ else if ( theCopy ) {
+ if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
+ srcElems.Append( elem );
+ }
+ else {
// reverse element as it was reversed by transformation
if ( nbNodes > 2 )
- aMesh->ChangeElementNodes( elem, nodes, nbNodes );
+ aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
}
}
+
+ PGroupIDs newGroupIDs;
+
+ if ( theMakeGroups && theCopy ||
+ theMakeGroups && theTargetMesh )
+ newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+
+ return newGroupIDs;
}
+
+////=======================================================================
+////function : Scale
+////purpose :
+////=======================================================================
+//
+//SMESH_MeshEditor::PGroupIDs
+//SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
+// const gp_Pnt& thePoint,
+// const std::list<double>& theScaleFact,
+// const bool theCopy,
+// const bool theMakeGroups,
+// SMESH_Mesh* theTargetMesh)
+//{
+// MESSAGE("Scale");
+// myLastCreatedElems.Clear();
+// myLastCreatedNodes.Clear();
+//
+// SMESH_MeshEditor targetMeshEditor( theTargetMesh );
+// SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
+// SMESHDS_Mesh* aMesh = GetMeshDS();
+//
+// double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
+// std::list<double>::const_iterator itS = theScaleFact.begin();
+// scaleX = (*itS);
+// if(theScaleFact.size()==1) {
+// scaleY = (*itS);
+// scaleZ= (*itS);
+// }
+// if(theScaleFact.size()==2) {
+// itS++;
+// scaleY = (*itS);
+// scaleZ= (*itS);
+// }
+// if(theScaleFact.size()>2) {
+// itS++;
+// scaleY = (*itS);
+// itS++;
+// scaleZ= (*itS);
+// }
+//
+// // map old node to new one
+// TNodeNodeMap nodeMap;
+//
+// // elements sharing moved nodes; those of them which have all
+// // nodes mirrored but are not in theElems are to be reversed
+// TIDSortedElemSet inverseElemSet;
+//
+// // source elements for each generated one
+// SMESH_SequenceOfElemPtr srcElems, srcNodes;
+//
+// // loop on theElems
+// TIDSortedElemSet::iterator itElem;
+// for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+// const SMDS_MeshElement* elem = *itElem;
+// if ( !elem )
+// continue;
+//
+// // loop on elem nodes
+// SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+// while ( itN->more() ) {
+//
+// // check if a node has been already transformed
+// const SMDS_MeshNode* node = cast2Node( itN->next() );
+// pair<TNodeNodeMap::iterator,bool> n2n_isnew =
+// nodeMap.insert( make_pair ( node, node ));
+// if ( !n2n_isnew.second )
+// continue;
+//
+// //double coord[3];
+// //coord[0] = node->X();
+// //coord[1] = node->Y();
+// //coord[2] = node->Z();
+// //theTrsf.Transforms( coord[0], coord[1], coord[2] );
+// double dx = (node->X() - thePoint.X()) * scaleX;
+// double dy = (node->Y() - thePoint.Y()) * scaleY;
+// double dz = (node->Z() - thePoint.Z()) * scaleZ;
+// if ( theTargetMesh ) {
+// //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
+// const SMDS_MeshNode * newNode =
+// aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+// n2n_isnew.first->second = newNode;
+// myLastCreatedNodes.Append(newNode);
+// srcNodes.Append( node );
+// }
+// else if ( theCopy ) {
+// //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+// const SMDS_MeshNode * newNode =
+// aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+// n2n_isnew.first->second = newNode;
+// myLastCreatedNodes.Append(newNode);
+// srcNodes.Append( node );
+// }
+// else {
+// //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
+// aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+// // node position on shape becomes invalid
+// const_cast< SMDS_MeshNode* > ( node )->SetPosition
+// ( SMDS_SpacePosition::originSpacePosition() );
+// }
+//
+// // keep inverse elements
+// //if ( !theCopy && !theTargetMesh && needReverse ) {
+// // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
+// // while ( invElemIt->more() ) {
+// // const SMDS_MeshElement* iel = invElemIt->next();
+// // inverseElemSet.insert( iel );
+// // }
+// //}
+// }
+// }
+//
+// // either create new elements or reverse mirrored ones
+// //if ( !theCopy && !needReverse && !theTargetMesh )
+// if ( !theCopy && !theTargetMesh )
+// return PGroupIDs();
+//
+// TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
+// for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
+// theElems.insert( *invElemIt );
+//
+// // replicate or reverse elements
+//
+// enum {
+// REV_TETRA = 0, // = nbNodes - 4
+// REV_PYRAMID = 1, // = nbNodes - 4
+// REV_PENTA = 2, // = nbNodes - 4
+// REV_FACE = 3,
+// REV_HEXA = 4, // = nbNodes - 4
+// FORWARD = 5
+// };
+// int index[][8] = {
+// { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
+// { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
+// { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
+// { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
+// { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
+// { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
+// };
+//
+// for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+// {
+// const SMDS_MeshElement* elem = *itElem;
+// if ( !elem || elem->GetType() == SMDSAbs_Node )
+// continue;
+//
+// int nbNodes = elem->NbNodes();
+// int elemType = elem->GetType();
+//
+// if (elem->IsPoly()) {
+// // Polygon or Polyhedral Volume
+// switch ( elemType ) {
+// case SMDSAbs_Face:
+// {
+// vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
+// int iNode = 0;
+// SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+// while (itN->more()) {
+// const SMDS_MeshNode* node =
+// static_cast<const SMDS_MeshNode*>(itN->next());
+// TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+// if (nodeMapIt == nodeMap.end())
+// break; // not all nodes transformed
+// //if (needReverse) {
+// // // reverse mirrored faces and volumes
+// // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
+// //} else {
+// poly_nodes[iNode] = (*nodeMapIt).second;
+// //}
+// iNode++;
+// }
+// if ( iNode != nbNodes )
+// continue; // not all nodes transformed
+//
+// if ( theTargetMesh ) {
+// myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
+// srcElems.Append( elem );
+// }
+// else if ( theCopy ) {
+// myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
+// srcElems.Append( elem );
+// }
+// else {
+// aMesh->ChangePolygonNodes(elem, poly_nodes);
+// }
+// }
+// break;
+// case SMDSAbs_Volume:
+// {
+// // ATTENTION: Reversing is not yet done!!!
+// const SMDS_VtkVolume* aPolyedre =
+// dynamic_cast<const SMDS_VtkVolume*>( elem );
+// if (!aPolyedre) {
+// MESSAGE("Warning: bad volumic element");
+// continue;
+// }
+//
+// vector<const SMDS_MeshNode*> poly_nodes;
+// vector<int> quantities;
+//
+// bool allTransformed = true;
+// int nbFaces = aPolyedre->NbFaces();
+// for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
+// int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+// for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
+// const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
+// TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+// if (nodeMapIt == nodeMap.end()) {
+// allTransformed = false; // not all nodes transformed
+// } else {
+// poly_nodes.push_back((*nodeMapIt).second);
+// }
+// }
+// quantities.push_back(nbFaceNodes);
+// }
+// if ( !allTransformed )
+// continue; // not all nodes transformed
+//
+// if ( theTargetMesh ) {
+// myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
+// srcElems.Append( elem );
+// }
+// else if ( theCopy ) {
+// myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
+// srcElems.Append( elem );
+// }
+// else {
+// aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
+// }
+// }
+// break;
+// default:;
+// }
+// continue;
+// }
+//
+// // Regular elements
+// int* i = index[ FORWARD ];
+// //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
+// // if ( elemType == SMDSAbs_Face )
+// // i = index[ REV_FACE ];
+// // else
+// // i = index[ nbNodes - 4 ];
+//
+// if(elem->IsQuadratic()) {
+// static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+// i = anIds;
+// //if(needReverse) {
+// // if(nbNodes==3) { // quadratic edge
+// // static int anIds[] = {1,0,2};
+// // i = anIds;
+// // }
+// // else if(nbNodes==6) { // quadratic triangle
+// // static int anIds[] = {0,2,1,5,4,3};
+// // i = anIds;
+// // }
+// // else if(nbNodes==8) { // quadratic quadrangle
+// // static int anIds[] = {0,3,2,1,7,6,5,4};
+// // i = anIds;
+// // }
+// // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
+// // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
+// // i = anIds;
+// // }
+// // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
+// // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
+// // i = anIds;
+// // }
+// // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
+// // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
+// // i = anIds;
+// // }
+// // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
+// // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
+// // i = anIds;
+// // }
+// //}
+// }
+//
+// // find transformed nodes
+// vector<const SMDS_MeshNode*> nodes(nbNodes);
+// int iNode = 0;
+// SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+// while ( itN->more() ) {
+// const SMDS_MeshNode* node =
+// static_cast<const SMDS_MeshNode*>( itN->next() );
+// TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
+// if ( nodeMapIt == nodeMap.end() )
+// break; // not all nodes transformed
+// nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
+// }
+// if ( iNode != nbNodes )
+// continue; // not all nodes transformed
+//
+// if ( theTargetMesh ) {
+// if ( SMDS_MeshElement* copy =
+// targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+// myLastCreatedElems.Append( copy );
+// srcElems.Append( elem );
+// }
+// }
+// else if ( theCopy ) {
+// if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+// myLastCreatedElems.Append( copy );
+// srcElems.Append( elem );
+// }
+// }
+// else {
+// // reverse element as it was reversed by transformation
+// if ( nbNodes > 2 )
+// aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+// }
+// }
+//
+// PGroupIDs newGroupIDs;
+//
+// if ( theMakeGroups && theCopy ||
+// theMakeGroups && theTargetMesh ) {
+// string groupPostfix = "scaled";
+// newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+// }
+//
+// return newGroupIDs;
+//}
+
+
//=======================================================================
-//function : FindCoincidentNodes
-//purpose : Return list of group of nodes close to each other within theTolerance
-// Search among theNodes or in the whole mesh if theNodes is empty.
+/*!
+ * \brief Create groups of elements made during transformation
+ * \param nodeGens - nodes making corresponding myLastCreatedNodes
+ * \param elemGens - elements making corresponding myLastCreatedElems
+ * \param postfix - to append to names of new groups
+ */
//=======================================================================
-void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
- const double theTolerance,
- TListOfListOfNodes & theGroupsOfNodes)
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
+ const SMESH_SequenceOfElemPtr& elemGens,
+ const std::string& postfix,
+ SMESH_Mesh* targetMesh)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ PGroupIDs newGroupIDs( new list<int> );
+ SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
- double tol2 = theTolerance * theTolerance;
+ // Sort existing groups by types and collect their names
- list<const SMDS_MeshNode*> nodes;
- if ( theNodes.empty() )
- { // get all nodes in the mesh
- SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
- while ( nIt->more() )
- nodes.push_back( nIt->next() );
- }
- else
- {
- nodes.insert( nodes.end(), theNodes.begin(), theNodes.end() );
+ // to store an old group and a generated new one
+ typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
+ vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
+ // group names
+ set< string > groupNames;
+ //
+ SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
+ SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
+ while ( groupIt->more() ) {
+ SMESH_Group * group = groupIt->next();
+ if ( !group ) continue;
+ SMESHDS_GroupBase* groupDS = group->GetGroupDS();
+ if ( !groupDS || groupDS->IsEmpty() ) continue;
+ groupNames.insert( group->GetName() );
+ groupDS->SetStoreName( group->GetName() );
+ groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
}
- list<const SMDS_MeshNode*>::iterator it2, it1 = nodes.begin();
- for ( ; it1 != nodes.end(); it1++ )
+ // Groups creation
+
+ // loop on nodes and elements
+ for ( int isNodes = 0; isNodes < 2; ++isNodes )
{
- const SMDS_MeshNode* n1 = *it1;
- gp_Pnt p1( n1->X(), n1->Y(), n1->Z() );
+ const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
+ const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
+ if ( gens.Length() != elems.Length() )
+ throw SALOME_Exception(LOCALIZED("invalid args"));
- list<const SMDS_MeshNode*> * groupPtr = 0;
- it2 = it1;
- for ( it2++; it2 != nodes.end(); it2++ )
+ // loop on created elements
+ for (int iElem = 1; iElem <= elems.Length(); ++iElem )
{
- const SMDS_MeshNode* n2 = *it2;
- gp_Pnt p2( n2->X(), n2->Y(), n2->Z() );
- if ( p1.SquareDistance( p2 ) <= tol2 )
+ const SMDS_MeshElement* sourceElem = gens( iElem );
+ if ( !sourceElem ) {
+ MESSAGE("generateGroups(): NULL source element");
+ continue;
+ }
+ list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
+ if ( groupsOldNew.empty() ) {
+ while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
+ ++iElem; // skip all elements made by sourceElem
+ continue;
+ }
+ // collect all elements made by sourceElem
+ list< const SMDS_MeshElement* > resultElems;
+ if ( const SMDS_MeshElement* resElem = elems( iElem ))
+ if ( resElem != sourceElem )
+ resultElems.push_back( resElem );
+ while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
+ if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
+ if ( resElem != sourceElem )
+ resultElems.push_back( resElem );
+ // do not generate element groups from node ones
+ if ( sourceElem->GetType() == SMDSAbs_Node &&
+ elems( iElem )->GetType() != SMDSAbs_Node )
+ continue;
+
+ // add resultElems to groups made by ones the sourceElem belongs to
+ list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
+ for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
{
- if ( !groupPtr ) {
- theGroupsOfNodes.push_back( list<const SMDS_MeshNode*>() );
- groupPtr = & theGroupsOfNodes.back();
- groupPtr->push_back( n1 );
+ SMESHDS_GroupBase* oldGroup = gOldNew->first;
+ if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
+ {
+ SMDS_MeshGroup* & newGroup = gOldNew->second;
+ if ( !newGroup )// create a new group
+ {
+ // make a name
+ string name = oldGroup->GetStoreName();
+ if ( !targetMesh ) {
+ name += "_";
+ name += postfix;
+ int nb = 0;
+ while ( !groupNames.insert( name ).second ) // name exists
+ {
+ if ( nb == 0 ) {
+ name += "_1";
+ }
+ else {
+ TCollection_AsciiString nbStr(nb+1);
+ name.resize( name.rfind('_')+1 );
+ name += nbStr.ToCString();
+ }
+ ++nb;
+ }
+ }
+ // make a group
+ int id;
+ SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
+ name.c_str(), id );
+ SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
+ newGroup = & groupDS->SMDSGroup();
+ newGroupIDs->push_back( id );
+ }
+
+ // fill in a new group
+ list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
+ for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
+ newGroup->Add( *resElemIt );
}
- if(groupPtr->front()>n2)
- groupPtr->push_front( n2 );
- else
- groupPtr->push_back( n2 );
- it2 = nodes.erase( it2 );
- it2--;
}
- }
+ } // loop on created elements
+ }// loop on nodes and elements
+
+ return newGroupIDs;
+}
+
+//================================================================================
+/*!
+ * \brief Return list of group of nodes close to each other within theTolerance
+ * Search among theNodes or in the whole mesh if theNodes is empty using
+ * an Octree algorithm
+ */
+//================================================================================
+
+void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
+ const double theTolerance,
+ TListOfListOfNodes & theGroupsOfNodes)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ if ( theNodes.empty() )
+ { // get all nodes in the mesh
+ SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
+ while ( nIt->more() )
+ theNodes.insert( theNodes.end(),nIt->next());
}
+
+ SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
}
+
//=======================================================================
-//function : SimplifyFace
-//purpose :
+/*!
+ * \brief Implementation of search for the node closest to point
+ */
//=======================================================================
-int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
- vector<const SMDS_MeshNode *>& poly_nodes,
- vector<int>& quantities) const
-{
- int nbNodes = faceNodes.size();
- if (nbNodes < 3)
- return 0;
+struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
+{
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Constructor
+ */
+ SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
+ {
+ myMesh = ( SMESHDS_Mesh* ) theMesh;
- set<const SMDS_MeshNode*> nodeSet;
+ TIDSortedNodeSet nodes;
+ if ( theMesh ) {
+ SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
+ while ( nIt->more() )
+ nodes.insert( nodes.end(), nIt->next() );
+ }
+ myOctreeNode = new SMESH_OctreeNode(nodes) ;
- // get simple seq of nodes
- const SMDS_MeshNode* simpleNodes[ nbNodes ];
- int iSimple = 0, nbUnique = 0;
-
- simpleNodes[iSimple++] = faceNodes[0];
- nbUnique++;
- for (int iCur = 1; iCur < nbNodes; iCur++) {
- if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
- simpleNodes[iSimple++] = faceNodes[iCur];
- if (nodeSet.insert( faceNodes[iCur] ).second)
- nbUnique++;
+ // get max size of a leaf box
+ SMESH_OctreeNode* tree = myOctreeNode;
+ while ( !tree->isLeaf() )
+ {
+ SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
+ if ( cIt->more() )
+ tree = cIt->next();
}
+ myHalfLeafSize = tree->maxSize() / 2.;
}
- int nbSimple = iSimple;
- if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
- nbSimple--;
- iSimple--;
- }
-
- if (nbUnique < 3)
- return 0;
- // separate loops
- int nbNew = 0;
- bool foundLoop = (nbSimple > nbUnique);
- while (foundLoop) {
- foundLoop = false;
- set<const SMDS_MeshNode*> loopSet;
- for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
- const SMDS_MeshNode* n = simpleNodes[iSimple];
- if (!loopSet.insert( n ).second) {
- foundLoop = true;
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Move node and update myOctreeNode accordingly
+ */
+ void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
+ {
+ myOctreeNode->UpdateByMoveNode( node, toPnt );
+ myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
+ }
- // separate loop
- int iC = 0, curLast = iSimple;
- for (; iC < curLast; iC++) {
- if (simpleNodes[iC] == n) break;
- }
- int loopLen = curLast - iC;
- if (loopLen > 2) {
- // create sub-element
- nbNew++;
- quantities.push_back(loopLen);
- for (; iC < curLast; iC++) {
- poly_nodes.push_back(simpleNodes[iC]);
- }
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Do it's job
+ */
+ const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
+ {
+ map<double, const SMDS_MeshNode*> dist2Nodes;
+ myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
+ if ( !dist2Nodes.empty() )
+ return dist2Nodes.begin()->second;
+ list<const SMDS_MeshNode*> nodes;
+ //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
+
+ double minSqDist = DBL_MAX;
+ if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
+ {
+ // sort leafs by their distance from thePnt
+ typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
+ TDistTreeMap treeMap;
+ list< SMESH_OctreeNode* > treeList;
+ list< SMESH_OctreeNode* >::iterator trIt;
+ treeList.push_back( myOctreeNode );
+
+ gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
+ bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
+ for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
+ {
+ SMESH_OctreeNode* tree = *trIt;
+ if ( !tree->isLeaf() ) // put children to the queue
+ {
+ if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
+ SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
+ while ( cIt->more() )
+ treeList.push_back( cIt->next() );
}
- // shift the rest nodes (place from the first loop position)
- for (iC = curLast + 1; iC < nbSimple; iC++) {
- simpleNodes[iC - loopLen] = simpleNodes[iC];
+ else if ( tree->NbNodes() ) // put a tree to the treeMap
+ {
+ const Bnd_B3d& box = tree->getBox();
+ double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
+ pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
+ if ( !it_in.second ) // not unique distance to box center
+ treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
}
- nbSimple -= loopLen;
- iSimple -= loopLen;
}
- } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
- } // while (foundLoop)
-
- if (iSimple > 2) {
- nbNew++;
- quantities.push_back(iSimple);
- for (int i = 0; i < iSimple; i++)
- poly_nodes.push_back(simpleNodes[i]);
+ // find distance after which there is no sense to check tree's
+ double sqLimit = DBL_MAX;
+ TDistTreeMap::iterator sqDist_tree = treeMap.begin();
+ if ( treeMap.size() > 5 ) {
+ SMESH_OctreeNode* closestTree = sqDist_tree->second;
+ const Bnd_B3d& box = closestTree->getBox();
+ double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
+ sqLimit = limit * limit;
+ }
+ // get all nodes from trees
+ for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
+ if ( sqDist_tree->first > sqLimit )
+ break;
+ SMESH_OctreeNode* tree = sqDist_tree->second;
+ tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
+ }
+ }
+ // find closest among nodes
+ minSqDist = DBL_MAX;
+ const SMDS_MeshNode* closestNode = 0;
+ list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
+ for ( ; nIt != nodes.end(); ++nIt ) {
+ double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
+ if ( minSqDist > sqDist ) {
+ closestNode = *nIt;
+ minSqDist = sqDist;
+ }
+ }
+ return closestNode;
}
- return nbNew;
-}
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Destructor
+ */
+ ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
+
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Return the node tree
+ */
+ const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
+
+private:
+ SMESH_OctreeNode* myOctreeNode;
+ SMESHDS_Mesh* myMesh;
+ double myHalfLeafSize; // max size of a leaf box
+};
//=======================================================================
-//function : MergeNodes
-//purpose : In each group, the cdr of nodes are substituted by the first one
-// in all elements.
+/*!
+ * \brief Return SMESH_NodeSearcher
+ */
//=======================================================================
-void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
+SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ return new SMESH_NodeSearcherImpl( GetMeshDS() );
+}
- SMESHDS_Mesh* aMesh = GetMeshDS();
+// ========================================================================
+namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
+{
+ const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
+ const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
+ const double NodeRadius = 1e-9; // to enlarge bnd box of element
- TNodeNodeMap nodeNodeMap; // node to replace - new node
- set<const SMDS_MeshElement*> elems; // all elements with changed nodes
- list< int > rmElemIds, rmNodeIds;
+ //=======================================================================
+ /*!
+ * \brief Octal tree of bounding boxes of elements
+ */
+ //=======================================================================
- // Fill nodeNodeMap and elems
+ class ElementBndBoxTree : public SMESH_Octree
+ {
+ public:
+
+ ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
+ void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
+ void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
+ ~ElementBndBoxTree();
+
+ protected:
+ ElementBndBoxTree() {}
+ SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
+ void buildChildrenData();
+ Bnd_B3d* buildRootBox();
+ private:
+ //!< Bounding box of element
+ struct ElementBox : public Bnd_B3d
+ {
+ const SMDS_MeshElement* _element;
+ int _refCount; // an ElementBox can be included in several tree branches
+ ElementBox(const SMDS_MeshElement* elem, double tolerance);
+ };
+ vector< ElementBox* > _elements;
+ };
- TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
- for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
- list<const SMDS_MeshNode*>& nodes = *grIt;
- list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
- const SMDS_MeshNode* nToKeep = *nIt;
- for ( ; nIt != nodes.end(); nIt++ ) {
- const SMDS_MeshNode* nToRemove = *nIt;
- nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
- if ( nToRemove != nToKeep ) {
- rmNodeIds.push_back( nToRemove->GetID() );
- AddToSameGroups( nToKeep, nToRemove, aMesh );
- }
+ //================================================================================
+ /*!
+ * \brief ElementBndBoxTree creation
+ */
+ //================================================================================
- SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
- while ( invElemIt->more() ) {
- const SMDS_MeshElement* elem = invElemIt->next();
- elems.insert(elem);
- }
- }
+ ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
+ :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
+ {
+ int nbElems = mesh.GetMeshInfo().NbElements( elemType );
+ _elements.reserve( nbElems );
+
+ SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
+ while ( elemIt->more() )
+ _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
+
+ if ( _elements.size() > MaxNbElemsInLeaf )
+ compute();
+ else
+ myIsLeaf = true;
}
- // Change element nodes or remove an element
- set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
- for ( ; eIt != elems.end(); eIt++ ) {
- const SMDS_MeshElement* elem = *eIt;
- int nbNodes = elem->NbNodes();
- int aShapeId = FindShape( elem );
+ //================================================================================
+ /*!
+ * \brief Destructor
+ */
+ //================================================================================
- set<const SMDS_MeshNode*> nodeSet;
- const SMDS_MeshNode* curNodes[ nbNodes ], *uniqueNodes[ nbNodes ];
- int iUnique = 0, iCur = 0, nbRepl = 0, iRepl [ nbNodes ];
+ ElementBndBoxTree::~ElementBndBoxTree()
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ if ( --_elements[i]->_refCount <= 0 )
+ delete _elements[i];
+ }
- // get new seq of nodes
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() ) {
- const SMDS_MeshNode* n =
- static_cast<const SMDS_MeshNode*>( itN->next() );
+ //================================================================================
+ /*!
+ * \brief Return the maximal box
+ */
+ //================================================================================
- TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
- if ( nnIt != nodeNodeMap.end() ) { // n sticks
- n = (*nnIt).second;
- iRepl[ nbRepl++ ] = iCur;
+ Bnd_B3d* ElementBndBoxTree::buildRootBox()
+ {
+ Bnd_B3d* box = new Bnd_B3d;
+ for ( int i = 0; i < _elements.size(); ++i )
+ box->Add( *_elements[i] );
+ return box;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Redistrubute element boxes among children
+ */
+ //================================================================================
+
+ void ElementBndBoxTree::buildChildrenData()
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
+ {
+ _elements[i]->_refCount++;
+ ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
+ }
}
- curNodes[ iCur ] = n;
- bool isUnique = nodeSet.insert( n ).second;
- if ( isUnique )
- uniqueNodes[ iUnique++ ] = n;
- iCur++;
+ _elements[i]->_refCount--;
}
+ _elements.clear();
- // Analyse element topology after replacement
+ for (int j = 0; j < 8; j++)
+ {
+ ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
+ if ( child->_elements.size() <= MaxNbElemsInLeaf )
+ child->myIsLeaf = true;
- bool isOk = true;
- int nbUniqueNodes = nodeSet.size();
- if ( nbNodes != nbUniqueNodes ) { // some nodes stick
- // Polygons and Polyhedral volumes
- if (elem->IsPoly()) {
+ if ( child->_elements.capacity() - child->_elements.size() > 1000 )
+ child->_elements.resize( child->_elements.size() ); // compact
+ }
+ }
- if (elem->GetType() == SMDSAbs_Face) {
- // Polygon
- vector<const SMDS_MeshNode *> face_nodes (nbNodes);
- int inode = 0;
- for (; inode < nbNodes; inode++) {
- face_nodes[inode] = curNodes[inode];
- }
+ //================================================================================
+ /*!
+ * \brief Return elements which can include the point
+ */
+ //================================================================================
- vector<const SMDS_MeshNode *> polygons_nodes;
- vector<int> quantities;
- int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
+ void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
+ TIDSortedElemSet& foundElems)
+ {
+ if ( level() && getBox().IsOut( point.XYZ() ))
+ return;
- if (nbNew > 0) {
- inode = 0;
- for (int iface = 0; iface < nbNew - 1; iface++) {
- int nbNodes = quantities[iface];
- vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
- for (int ii = 0; ii < nbNodes; ii++, inode++) {
- poly_nodes[ii] = polygons_nodes[inode];
- }
- SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
- myLastCreatedElems.Append(newElem);
- if (aShapeId)
- aMesh->SetMeshElementOnShape(newElem, aShapeId);
- }
- aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
- }
- else {
- rmElemIds.push_back(elem->GetID());
- }
+ if ( isLeaf() )
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ if ( !_elements[i]->IsOut( point.XYZ() ))
+ foundElems.insert( _elements[i]->_element );
+ }
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
+ }
+ }
- }
- else if (elem->GetType() == SMDSAbs_Volume) {
- // Polyhedral volume
- if (nbUniqueNodes < 4) {
- rmElemIds.push_back(elem->GetID());
- }
- else {
- // each face has to be analized in order to check volume validity
- const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
- static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
- if (aPolyedre) {
- int nbFaces = aPolyedre->NbFaces();
+ //================================================================================
+ /*!
+ * \brief Return elements which can be intersected by the line
+ */
+ //================================================================================
- vector<const SMDS_MeshNode *> poly_nodes;
- vector<int> quantities;
+ void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
+ TIDSortedElemSet& foundElems)
+ {
+ if ( level() && getBox().IsOut( line ))
+ return;
- for (int iface = 1; iface <= nbFaces; iface++) {
- int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
- vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
+ if ( isLeaf() )
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ if ( !_elements[i]->IsOut( line ))
+ foundElems.insert( _elements[i]->_element );
+ }
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
+ }
+ }
- for (int inode = 1; inode <= nbFaceNodes; inode++) {
- const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
- TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
- if (nnIt != nodeNodeMap.end()) { // faceNode sticks
- faceNode = (*nnIt).second;
- }
- faceNodes[inode - 1] = faceNode;
- }
+ //================================================================================
+ /*!
+ * \brief Construct the element box
+ */
+ //================================================================================
- SimplifyFace(faceNodes, poly_nodes, quantities);
- }
+ ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
+ {
+ _element = elem;
+ _refCount = 1;
+ SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
+ while ( nIt->more() )
+ Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
+ Enlarge( tolerance );
+ }
- if (quantities.size() > 3) {
- // to be done: remove coincident faces
- }
+} // namespace
- if (quantities.size() > 3)
- aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
- else
- rmElemIds.push_back(elem->GetID());
+//=======================================================================
+/*!
+ * \brief Implementation of search for the elements by point and
+ * of classification of point in 2D mesh
+ */
+//=======================================================================
- }
- else {
- rmElemIds.push_back(elem->GetID());
- }
- }
- }
- else {
- }
+struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
+{
+ SMESHDS_Mesh* _mesh;
+ SMDS_ElemIteratorPtr _meshPartIt;
+ ElementBndBoxTree* _ebbTree;
+ SMESH_NodeSearcherImpl* _nodeSearcher;
+ SMDSAbs_ElementType _elementType;
+ double _tolerance;
+ bool _outerFacesFound;
+ set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
+
+ SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
+ : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
+ ~SMESH_ElementSearcherImpl()
+ {
+ if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
+ if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
+ }
+ virtual int FindElementsByPoint(const gp_Pnt& point,
+ SMDSAbs_ElementType type,
+ vector< const SMDS_MeshElement* >& foundElements);
+ virtual TopAbs_State GetPointState(const gp_Pnt& point);
+
+ void GetElementsNearLine( const gp_Ax1& line,
+ SMDSAbs_ElementType type,
+ vector< const SMDS_MeshElement* >& foundElems);
+ double getTolerance();
+ bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
+ const double tolerance, double & param);
+ void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
+ bool isOuterBoundary(const SMDS_MeshElement* face) const
+ {
+ return _outerFaces.empty() || _outerFaces.count(face);
+ }
+ struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
+ {
+ const SMDS_MeshElement* _face;
+ gp_Vec _faceNorm;
+ bool _coincides; //!< the line lays in face plane
+ TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
+ : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
+ };
+ struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
+ {
+ SMESH_TLink _link;
+ TIDSortedElemSet _faces;
+ TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
+ : _link( n1, n2 ), _faces( &face, &face + 1) {}
+ };
+};
- continue;
- }
+ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
+{
+ return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
+ << ", _coincides="<<i._coincides << ")";
+}
- // Regular elements
- switch ( nbNodes ) {
- case 2: ///////////////////////////////////// EDGE
- isOk = false; break;
- case 3: ///////////////////////////////////// TRIANGLE
- isOk = false; break;
- case 4:
- if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
- isOk = false;
+//=======================================================================
+/*!
+ * \brief define tolerance for search
+ */
+//=======================================================================
+
+double SMESH_ElementSearcherImpl::getTolerance()
+{
+ if ( _tolerance < 0 )
+ {
+ const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
+
+ _tolerance = 0;
+ if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
+ {
+ double boxSize = _nodeSearcher->getTree()->maxSize();
+ _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
+ }
+ else if ( _ebbTree && meshInfo.NbElements() > 0 )
+ {
+ double boxSize = _ebbTree->maxSize();
+ _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
+ }
+ if ( _tolerance == 0 )
+ {
+ // define tolerance by size of a most complex element
+ int complexType = SMDSAbs_Volume;
+ while ( complexType > SMDSAbs_All &&
+ meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
+ --complexType;
+ if ( complexType == SMDSAbs_All ) return 0; // empty mesh
+ double elemSize;
+ if ( complexType == int( SMDSAbs_Node ))
+ {
+ SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
+ elemSize = 1;
+ if ( meshInfo.NbNodes() > 2 )
+ elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
+ }
+ else
+ {
+ SMDS_ElemIteratorPtr elemIt =
+ _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
+ const SMDS_MeshElement* elem = elemIt->next();
+ SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+ SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
+ while ( nodeIt->more() )
+ {
+ double dist = n1.Distance( cast2Node( nodeIt->next() ));
+ elemSize = max( dist, elemSize );
+ }
+ }
+ _tolerance = 1e-4 * elemSize;
+ }
+ }
+ return _tolerance;
+}
+
+//================================================================================
+/*!
+ * \brief Find intersection of the line and an edge of face and return parameter on line
+ */
+//================================================================================
+
+bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
+ const SMDS_MeshElement* face,
+ const double tol,
+ double & param)
+{
+ int nbInts = 0;
+ param = 0;
+
+ GeomAPI_ExtremaCurveCurve anExtCC;
+ Handle(Geom_Curve) lineCurve = new Geom_Line( line );
+
+ int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
+ for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
+ {
+ GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
+ SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
+ anExtCC.Init( lineCurve, edge);
+ if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
+ {
+ Quantity_Parameter pl, pe;
+ anExtCC.LowerDistanceParameters( pl, pe );
+ param += pl;
+ if ( ++nbInts == 2 )
+ break;
+ }
+ }
+ if ( nbInts > 0 ) param /= nbInts;
+ return nbInts > 0;
+}
+//================================================================================
+/*!
+ * \brief Find all faces belonging to the outer boundary of mesh
+ */
+//================================================================================
+
+void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
+{
+ if ( _outerFacesFound ) return;
+
+ // Collect all outer faces by passing from one outer face to another via their links
+ // and BTW find out if there are internal faces at all.
+
+ // checked links and links where outer boundary meets internal one
+ set< SMESH_TLink > visitedLinks, seamLinks;
+
+ // links to treat with already visited faces sharing them
+ list < TFaceLink > startLinks;
+
+ // load startLinks with the first outerFace
+ startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
+ _outerFaces.insert( outerFace );
+
+ TIDSortedElemSet emptySet;
+ while ( !startLinks.empty() )
+ {
+ const SMESH_TLink& link = startLinks.front()._link;
+ TIDSortedElemSet& faces = startLinks.front()._faces;
+
+ outerFace = *faces.begin();
+ // find other faces sharing the link
+ const SMDS_MeshElement* f;
+ while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
+ faces.insert( f );
+
+ // select another outer face among the found
+ const SMDS_MeshElement* outerFace2 = 0;
+ if ( faces.size() == 2 )
+ {
+ outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
+ }
+ else if ( faces.size() > 2 )
+ {
+ seamLinks.insert( link );
+
+ // link direction within the outerFace
+ gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
+ SMESH_MeshEditor::TNodeXYZ( link.node2()));
+ int i1 = outerFace->GetNodeIndex( link.node1() );
+ int i2 = outerFace->GetNodeIndex( link.node2() );
+ bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
+ if ( rev ) n1n2.Reverse();
+ // outerFace normal
+ gp_XYZ ofNorm, fNorm;
+ if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
+ {
+ // direction from the link inside outerFace
+ gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
+ // sort all other faces by angle with the dirInOF
+ map< double, const SMDS_MeshElement* > angle2Face;
+ set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
+ for ( ; face != faces.end(); ++face )
+ {
+ if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
+ continue;
+ gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
+ double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
+ if ( angle < 0 ) angle += 2*PI;
+ angle2Face.insert( make_pair( angle, *face ));
+ }
+ if ( !angle2Face.empty() )
+ outerFace2 = angle2Face.begin()->second;
+ }
+ }
+ // store the found outer face and add its links to continue seaching from
+ if ( outerFace2 )
+ {
+ _outerFaces.insert( outerFace );
+ int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
+ for ( int i = 0; i < nbNodes; ++i )
+ {
+ SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
+ if ( visitedLinks.insert( link2 ).second )
+ startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
+ }
+ }
+ startLinks.pop_front();
+ }
+ _outerFacesFound = true;
+
+ if ( !seamLinks.empty() )
+ {
+ // There are internal boundaries touching the outher one,
+ // find all faces of internal boundaries in order to find
+ // faces of boundaries of holes, if any.
+
+ }
+ else
+ {
+ _outerFaces.clear();
+ }
+}
+
+//=======================================================================
+/*!
+ * \brief Find elements of given type where the given point is IN or ON.
+ * Returns nb of found elements and elements them-selves.
+ *
+ * 'ALL' type means elements of any type excluding nodes and 0D elements
+ */
+//=======================================================================
+
+int SMESH_ElementSearcherImpl::
+FindElementsByPoint(const gp_Pnt& point,
+ SMDSAbs_ElementType type,
+ vector< const SMDS_MeshElement* >& foundElements)
+{
+ foundElements.clear();
+
+ double tolerance = getTolerance();
+
+ // =================================================================================
+ if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
+ {
+ if ( !_nodeSearcher )
+ _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
+
+ const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
+ if ( !closeNode ) return foundElements.size();
+
+ if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
+ return foundElements.size(); // to far from any node
+
+ if ( type == SMDSAbs_Node )
+ {
+ foundElements.push_back( closeNode );
+ }
+ else
+ {
+ SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
+ while ( elemIt->more() )
+ foundElements.push_back( elemIt->next() );
+ }
+ }
+ // =================================================================================
+ else // elements more complex than 0D
+ {
+ if ( !_ebbTree || _elementType != type )
+ {
+ if ( _ebbTree ) delete _ebbTree;
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
+ }
+ TIDSortedElemSet suspectElems;
+ _ebbTree->getElementsNearPoint( point, suspectElems );
+ TIDSortedElemSet::iterator elem = suspectElems.begin();
+ for ( ; elem != suspectElems.end(); ++elem )
+ if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
+ foundElements.push_back( *elem );
+ }
+ return foundElements.size();
+}
+
+//================================================================================
+/*!
+ * \brief Classify the given point in the closed 2D mesh
+ */
+//================================================================================
+
+TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
+{
+ double tolerance = getTolerance();
+ if ( !_ebbTree || _elementType != SMDSAbs_Face )
+ {
+ if ( _ebbTree ) delete _ebbTree;
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
+ }
+ // Algo: analyse transition of a line starting at the point through mesh boundary;
+ // try three lines parallel to axis of the coordinate system and perform rough
+ // analysis. If solution is not clear perform thorough analysis.
+
+ const int nbAxes = 3;
+ gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
+ map< double, TInters > paramOnLine2TInters[ nbAxes ];
+ list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
+ multimap< int, int > nbInt2Axis; // to find the simplest case
+ for ( int axis = 0; axis < nbAxes; ++axis )
+ {
+ gp_Ax1 lineAxis( point, axisDir[axis]);
+ gp_Lin line ( lineAxis );
+
+ TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
+ _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
+
+ // Intersect faces with the line
+
+ map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+ TIDSortedElemSet::iterator face = suspectFaces.begin();
+ for ( ; face != suspectFaces.end(); ++face )
+ {
+ // get face plane
+ gp_XYZ fNorm;
+ if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
+ gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
+
+ // perform intersection
+ IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
+ if ( !intersection.IsDone() )
+ continue;
+ if ( intersection.IsInQuadric() )
+ {
+ tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
+ }
+ else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
+ {
+ gp_Pnt intersectionPoint = intersection.Point(1);
+ if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
+ u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
+ }
+ }
+ // Analyse intersections roughly
+
+ int nbInter = u2inters.size();
+ if ( nbInter == 0 )
+ return TopAbs_OUT;
+
+ double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
+ if ( nbInter == 1 ) // not closed mesh
+ return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
+
+ if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
+ return TopAbs_ON;
+
+ if ( (f<0) == (l<0) )
+ return TopAbs_OUT;
+
+ int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
+ int nbIntAfterPoint = nbInter - nbIntBeforePoint;
+ if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
+ return TopAbs_IN;
+
+ nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
+
+ if ( _outerFacesFound ) break; // pass to thorough analysis
+
+ } // three attempts - loop on CS axes
+
+ // Analyse intersections thoroughly.
+ // We make two loops maximum, on the first one we only exclude touching intersections,
+ // on the second, if situation is still unclear, we gather and use information on
+ // position of faces (internal or outer). If faces position is already gathered,
+ // we make the second loop right away.
+
+ for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
+ {
+ multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
+ for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
+ {
+ int axis = nb_axis->second;
+ map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+
+ gp_Ax1 lineAxis( point, axisDir[axis]);
+ gp_Lin line ( lineAxis );
+
+ // add tangent intersections to u2inters
+ double param;
+ list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
+ for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
+ if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
+ u2inters.insert(make_pair( param, *tgtInt ));
+ tangentInters[ axis ].clear();
+
+ // Count intersections before and after the point excluding touching ones.
+ // If hasPositionInfo we count intersections of outer boundary only
+
+ int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
+ double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
+ map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
+ bool ok = ! u_int1->second._coincides;
+ while ( ok && u_int1 != u2inters.end() )
+ {
+ double u = u_int1->first;
+ bool touchingInt = false;
+ if ( ++u_int2 != u2inters.end() )
+ {
+ // skip intersections at the same point (if the line passes through edge or node)
+ int nbSamePnt = 0;
+ while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
+ {
+ ++nbSamePnt;
+ ++u_int2;
+ }
+
+ // skip tangent intersections
+ int nbTgt = 0;
+ const SMDS_MeshElement* prevFace = u_int1->second._face;
+ while ( ok && u_int2->second._coincides )
+ {
+ if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
+ ok = false;
+ else
+ {
+ nbTgt++;
+ u_int2++;
+ ok = ( u_int2 != u2inters.end() );
+ }
+ }
+ if ( !ok ) break;
+
+ // skip intersections at the same point after tangent intersections
+ if ( nbTgt > 0 )
+ {
+ double u2 = u_int2->first;
+ ++u_int2;
+ while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
+ {
+ ++nbSamePnt;
+ ++u_int2;
+ }
+ }
+ // decide if we skipped a touching intersection
+ if ( nbSamePnt + nbTgt > 0 )
+ {
+ double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
+ map< double, TInters >::iterator u_int = u_int1;
+ for ( ; u_int != u_int2; ++u_int )
+ {
+ if ( u_int->second._coincides ) continue;
+ double dot = u_int->second._faceNorm * line.Direction();
+ if ( dot > maxDot ) maxDot = dot;
+ if ( dot < minDot ) minDot = dot;
+ }
+ touchingInt = ( minDot*maxDot < 0 );
+ }
+ }
+ if ( !touchingInt )
+ {
+ if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
+ {
+ if ( u < 0 )
+ ++nbIntBeforePoint;
+ else
+ ++nbIntAfterPoint;
+ }
+ if ( u < f ) f = u;
+ if ( u > l ) l = u;
+ }
+
+ u_int1 = u_int2; // to next intersection
+
+ } // loop on intersections with one line
+
+ if ( ok )
+ {
+ if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
+ return TopAbs_ON;
+
+ if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
+ return TopAbs_OUT;
+
+ if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
+ return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
+
+ if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
+ return TopAbs_IN;
+
+ if ( (f<0) == (l<0) )
+ return TopAbs_OUT;
+
+ if ( hasPositionInfo )
+ return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
+ }
+ } // loop on intersections of the tree lines - thorough analysis
+
+ if ( !hasPositionInfo )
+ {
+ // gather info on faces position - is face in the outer boundary or not
+ map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
+ findOuterBoundary( u2inters.begin()->second._face );
+ }
+
+ } // two attempts - with and w/o faces position info in the mesh
+
+ return TopAbs_UNKNOWN;
+}
+
+//=======================================================================
+/*!
+ * \brief Return elements possibly intersecting the line
+ */
+//=======================================================================
+
+void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
+ SMDSAbs_ElementType type,
+ vector< const SMDS_MeshElement* >& foundElems)
+{
+ if ( !_ebbTree || _elementType != type )
+ {
+ if ( _ebbTree ) delete _ebbTree;
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
+ }
+ TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
+ _ebbTree->getElementsNearLine( line, suspectFaces );
+ foundElems.assign( suspectFaces.begin(), suspectFaces.end());
+}
+
+//=======================================================================
+/*!
+ * \brief Return SMESH_ElementSearcher
+ */
+//=======================================================================
+
+SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
+{
+ return new SMESH_ElementSearcherImpl( *GetMeshDS() );
+}
+
+//=======================================================================
+/*!
+ * \brief Return SMESH_ElementSearcher
+ */
+//=======================================================================
+
+SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
+{
+ return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
+}
+
+//=======================================================================
+/*!
+ * \brief Return true if the point is IN or ON of the element
+ */
+//=======================================================================
+
+bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
+{
+ if ( element->GetType() == SMDSAbs_Volume)
+ {
+ return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
+ }
+
+ // get ordered nodes
+
+ vector< gp_XYZ > xyz;
+ vector<const SMDS_MeshNode*> nodeList;
+
+ SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
+ if ( element->IsQuadratic() ) {
+ if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
+ nodeIt = f->interlacedNodesElemIterator();
+ else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
+ nodeIt = e->interlacedNodesElemIterator();
+ }
+ while ( nodeIt->more() )
+ {
+ const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
+ xyz.push_back( TNodeXYZ(node) );
+ nodeList.push_back(node);
+ }
+
+ int i, nbNodes = element->NbNodes();
+
+ if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
+ {
+ // compute face normal
+ gp_Vec faceNorm(0,0,0);
+ xyz.push_back( xyz.front() );
+ nodeList.push_back( nodeList.front() );
+ for ( i = 0; i < nbNodes; ++i )
+ {
+ gp_Vec edge1( xyz[i+1], xyz[i]);
+ gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
+ faceNorm += edge1 ^ edge2;
+ }
+ double normSize = faceNorm.Magnitude();
+ if ( normSize <= tol )
+ {
+ // degenerated face: point is out if it is out of all face edges
+ for ( i = 0; i < nbNodes; ++i )
+ {
+ SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
+ if ( !isOut( &edge, point, tol ))
+ return false;
+ }
+ return true;
+ }
+ faceNorm /= normSize;
+
+ // check if the point lays on face plane
+ gp_Vec n2p( xyz[0], point );
+ if ( fabs( n2p * faceNorm ) > tol )
+ return true; // not on face plane
+
+ // check if point is out of face boundary:
+ // define it by closest transition of a ray point->infinity through face boundary
+ // on the face plane.
+ // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
+ // to find intersections of the ray with the boundary.
+ gp_Vec ray = n2p;
+ gp_Vec plnNorm = ray ^ faceNorm;
+ normSize = plnNorm.Magnitude();
+ if ( normSize <= tol ) return false; // point coincides with the first node
+ plnNorm /= normSize;
+ // for each node of the face, compute its signed distance to the plane
+ vector<double> dist( nbNodes + 1);
+ for ( i = 0; i < nbNodes; ++i )
+ {
+ gp_Vec n2p( xyz[i], point );
+ dist[i] = n2p * plnNorm;
+ }
+ dist.back() = dist.front();
+ // find the closest intersection
+ int iClosest = -1;
+ double rClosest, distClosest = 1e100;;
+ gp_Pnt pClosest;
+ for ( i = 0; i < nbNodes; ++i )
+ {
+ double r;
+ if ( fabs( dist[i]) < tol )
+ r = 0.;
+ else if ( fabs( dist[i+1]) < tol )
+ r = 1.;
+ else if ( dist[i] * dist[i+1] < 0 )
+ r = dist[i] / ( dist[i] - dist[i+1] );
+ else
+ continue; // no intersection
+ gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
+ gp_Vec p2int ( point, pInt);
+ if ( p2int * ray > -tol ) // right half-space
+ {
+ double intDist = p2int.SquareMagnitude();
+ if ( intDist < distClosest )
+ {
+ iClosest = i;
+ rClosest = r;
+ pClosest = pInt;
+ distClosest = intDist;
+ }
+ }
+ }
+ if ( iClosest < 0 )
+ return true; // no intesections - out
+
+ // analyse transition
+ gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
+ gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
+ gp_Vec p2int ( point, pClosest );
+ bool out = (edgeNorm * p2int) < -tol;
+ if ( rClosest > 0. && rClosest < 1. ) // not node intersection
+ return out;
+
+ // ray pass through a face node; analyze transition through an adjacent edge
+ gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
+ gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
+ gp_Vec edgeAdjacent( p1, p2 );
+ gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
+ bool out2 = (edgeNorm2 * p2int) < -tol;
+
+ bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
+ return covexCorner ? (out || out2) : (out && out2);
+ }
+ if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
+ {
+ // point is out of edge if it is NOT ON any straight part of edge
+ // (we consider quadratic edge as being composed of two straight parts)
+ for ( i = 1; i < nbNodes; ++i )
+ {
+ gp_Vec edge( xyz[i-1], xyz[i]);
+ gp_Vec n1p ( xyz[i-1], point);
+ double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
+ if ( dist > tol )
+ continue;
+ gp_Vec n2p( xyz[i], point );
+ if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
+ continue;
+ return false; // point is ON this part
+ }
+ return true;
+ }
+ // Node or 0D element -------------------------------------------------------------------------
+ {
+ gp_Vec n2p ( xyz[0], point );
+ return n2p.Magnitude() <= tol;
+ }
+ return true;
+}
+
+//=======================================================================
+//function : SimplifyFace
+//purpose :
+//=======================================================================
+int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
+ vector<const SMDS_MeshNode *>& poly_nodes,
+ vector<int>& quantities) const
+{
+ int nbNodes = faceNodes.size();
+
+ if (nbNodes < 3)
+ return 0;
+
+ set<const SMDS_MeshNode*> nodeSet;
+
+ // get simple seq of nodes
+ //const SMDS_MeshNode* simpleNodes[ nbNodes ];
+ vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
+ int iSimple = 0, nbUnique = 0;
+
+ simpleNodes[iSimple++] = faceNodes[0];
+ nbUnique++;
+ for (int iCur = 1; iCur < nbNodes; iCur++) {
+ if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
+ simpleNodes[iSimple++] = faceNodes[iCur];
+ if (nodeSet.insert( faceNodes[iCur] ).second)
+ nbUnique++;
+ }
+ }
+ int nbSimple = iSimple;
+ if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
+ nbSimple--;
+ iSimple--;
+ }
+
+ if (nbUnique < 3)
+ return 0;
+
+ // separate loops
+ int nbNew = 0;
+ bool foundLoop = (nbSimple > nbUnique);
+ while (foundLoop) {
+ foundLoop = false;
+ set<const SMDS_MeshNode*> loopSet;
+ for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
+ const SMDS_MeshNode* n = simpleNodes[iSimple];
+ if (!loopSet.insert( n ).second) {
+ foundLoop = true;
+
+ // separate loop
+ int iC = 0, curLast = iSimple;
+ for (; iC < curLast; iC++) {
+ if (simpleNodes[iC] == n) break;
+ }
+ int loopLen = curLast - iC;
+ if (loopLen > 2) {
+ // create sub-element
+ nbNew++;
+ quantities.push_back(loopLen);
+ for (; iC < curLast; iC++) {
+ poly_nodes.push_back(simpleNodes[iC]);
+ }
+ }
+ // shift the rest nodes (place from the first loop position)
+ for (iC = curLast + 1; iC < nbSimple; iC++) {
+ simpleNodes[iC - loopLen] = simpleNodes[iC];
+ }
+ nbSimple -= loopLen;
+ iSimple -= loopLen;
+ }
+ } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
+ } // while (foundLoop)
+
+ if (iSimple > 2) {
+ nbNew++;
+ quantities.push_back(iSimple);
+ for (int i = 0; i < iSimple; i++)
+ poly_nodes.push_back(simpleNodes[i]);
+ }
+
+ return nbNew;
+}
+
+//=======================================================================
+//function : MergeNodes
+//purpose : In each group, the cdr of nodes are substituted by the first one
+// in all elements.
+//=======================================================================
+
+void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
+{
+ MESSAGE("MergeNodes");
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ TNodeNodeMap nodeNodeMap; // node to replace - new node
+ set<const SMDS_MeshElement*> elems; // all elements with changed nodes
+ list< int > rmElemIds, rmNodeIds;
+
+ // Fill nodeNodeMap and elems
+
+ TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
+ for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
+ list<const SMDS_MeshNode*>& nodes = *grIt;
+ list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
+ const SMDS_MeshNode* nToKeep = *nIt;
+ //MESSAGE("node to keep " << nToKeep->GetID());
+ for ( ++nIt; nIt != nodes.end(); nIt++ ) {
+ const SMDS_MeshNode* nToRemove = *nIt;
+ nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
+ if ( nToRemove != nToKeep ) {
+ //MESSAGE(" node to remove " << nToRemove->GetID());
+ rmNodeIds.push_back( nToRemove->GetID() );
+ AddToSameGroups( nToKeep, nToRemove, aMesh );
+ }
+
+ SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
+ while ( invElemIt->more() ) {
+ const SMDS_MeshElement* elem = invElemIt->next();
+ elems.insert(elem);
+ }
+ }
+ }
+ // Change element nodes or remove an element
+
+ set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
+ for ( ; eIt != elems.end(); eIt++ ) {
+ const SMDS_MeshElement* elem = *eIt;
+ //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
+ int nbNodes = elem->NbNodes();
+ int aShapeId = FindShape( elem );
+
+ set<const SMDS_MeshNode*> nodeSet;
+ vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
+ int iUnique = 0, iCur = 0, nbRepl = 0;
+ vector<int> iRepl( nbNodes );
+
+ // get new seq of nodes
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+ const SMDS_MeshNode* n =
+ static_cast<const SMDS_MeshNode*>( itN->next() );
+
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
+ if ( nnIt != nodeNodeMap.end() ) { // n sticks
+ n = (*nnIt).second;
+ // BUG 0020185: begin
+ {
+ bool stopRecur = false;
+ set<const SMDS_MeshNode*> nodesRecur;
+ nodesRecur.insert(n);
+ while (!stopRecur) {
+ TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
+ if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
+ n = (*nnIt_i).second;
+ if (!nodesRecur.insert(n).second) {
+ // error: recursive dependancy
+ stopRecur = true;
+ }
+ }
+ else
+ stopRecur = true;
+ }
+ }
+ // BUG 0020185: end
+ iRepl[ nbRepl++ ] = iCur;
+ }
+ curNodes[ iCur ] = n;
+ bool isUnique = nodeSet.insert( n ).second;
+ if ( isUnique )
+ uniqueNodes[ iUnique++ ] = n;
+ iCur++;
+ }
+
+ // Analyse element topology after replacement
+
+ bool isOk = true;
+ int nbUniqueNodes = nodeSet.size();
+ //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
+ if ( nbNodes != nbUniqueNodes ) { // some nodes stick
+ // Polygons and Polyhedral volumes
+ if (elem->IsPoly()) {
+
+ if (elem->GetType() == SMDSAbs_Face) {
+ // Polygon
+ vector<const SMDS_MeshNode *> face_nodes (nbNodes);
+ int inode = 0;
+ for (; inode < nbNodes; inode++) {
+ face_nodes[inode] = curNodes[inode];
+ }
+
+ vector<const SMDS_MeshNode *> polygons_nodes;
+ vector<int> quantities;
+ int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
+ if (nbNew > 0) {
+ inode = 0;
+ for (int iface = 0; iface < nbNew; iface++) {
+ int nbNodes = quantities[iface];
+ vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
+ for (int ii = 0; ii < nbNodes; ii++, inode++) {
+ poly_nodes[ii] = polygons_nodes[inode];
+ }
+ SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
+ myLastCreatedElems.Append(newElem);
+ if (aShapeId)
+ aMesh->SetMeshElementOnShape(newElem, aShapeId);
+ }
+
+ MESSAGE("ChangeElementNodes MergeNodes Polygon");
+ //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
+ vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
+ int quid =0;
+ if (nbNew > 0) quid = nbNew - 1;
+ vector<int> newquant(quantities.begin()+quid, quantities.end());
+ const SMDS_MeshElement* newElem = 0;
+ newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
+ myLastCreatedElems.Append(newElem);
+ if ( aShapeId && newElem )
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ rmElemIds.push_back(elem->GetID());
+ }
+ else {
+ rmElemIds.push_back(elem->GetID());
+ }
+
+ }
+ else if (elem->GetType() == SMDSAbs_Volume) {
+ // Polyhedral volume
+ if (nbUniqueNodes < 4) {
+ rmElemIds.push_back(elem->GetID());
+ }
+ else {
+ // each face has to be analyzed in order to check volume validity
+ const SMDS_VtkVolume* aPolyedre =
+ dynamic_cast<const SMDS_VtkVolume*>( elem );
+ if (aPolyedre) {
+ int nbFaces = aPolyedre->NbFaces();
+
+ vector<const SMDS_MeshNode *> poly_nodes;
+ vector<int> quantities;
+
+ for (int iface = 1; iface <= nbFaces; iface++) {
+ int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+ vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
+
+ for (int inode = 1; inode <= nbFaceNodes; inode++) {
+ const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
+ if (nnIt != nodeNodeMap.end()) { // faceNode sticks
+ faceNode = (*nnIt).second;
+ }
+ faceNodes[inode - 1] = faceNode;
+ }
+
+ SimplifyFace(faceNodes, poly_nodes, quantities);
+ }
+
+ if (quantities.size() > 3) {
+ // to be done: remove coincident faces
+ }
+
+ if (quantities.size() > 3)
+ {
+ MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
+ //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
+ const SMDS_MeshElement* newElem = 0;
+ newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
+ myLastCreatedElems.Append(newElem);
+ if ( aShapeId && newElem )
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ rmElemIds.push_back(elem->GetID());
+ }
+ }
+ else {
+ rmElemIds.push_back(elem->GetID());
+ }
+ }
+ }
+ else {
+ }
+
+ continue;
+ }
+
+ // Regular elements
+ // TODO not all the possible cases are solved. Find something more generic?
+ switch ( nbNodes ) {
+ case 2: ///////////////////////////////////// EDGE
+ isOk = false; break;
+ case 3: ///////////////////////////////////// TRIANGLE
+ isOk = false; break;
+ case 4:
+ if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
+ isOk = false;
else { //////////////////////////////////// QUADRANGLE
if ( nbUniqueNodes < 3 )
isOk = false;
else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
isOk = false; // opposite nodes stick
+ //MESSAGE("isOk " << isOk);
}
break;
case 6: ///////////////////////////////////// PENTAHEDRON
else
isOk = false;
break;
- case 8: {
+ case 8: {
if(elem->IsQuadratic()) { // Quadratic quadrangle
// 1 5 2
// +---+---+
// +---+---+
// 0 7 3
isOk = false;
+ if(nbRepl==2) {
+ MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
+ }
if(nbRepl==3) {
+ MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
nbUniqueNodes = 6;
if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
uniqueNodes[0] = curNodes[0];
isOk = true;
}
}
+ if(nbRepl==4) {
+ MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
+ }
+ if(nbRepl==5) {
+ MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
+ }
break;
}
//////////////////////////////////// HEXAHEDRON
if ( isOk ) {
if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
// Change nodes of polyedre
- const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
- static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
+ const SMDS_VtkVolume* aPolyedre =
+ dynamic_cast<const SMDS_VtkVolume*>( elem );
if (aPolyedre) {
int nbFaces = aPolyedre->NbFaces();
}
}
else {
- // Change regular element or polygon
- aMesh->ChangeElementNodes( elem, uniqueNodes, nbUniqueNodes );
+ //int elemId = elem->GetID();
+ //MESSAGE("Change regular element or polygon " << elemId);
+ SMDSAbs_ElementType etyp = elem->GetType();
+ uniqueNodes.resize(nbUniqueNodes);
+ SMDS_MeshElement* newElem = 0;
+ if (elem->GetEntityType() == SMDSEntity_Polygon)
+ newElem = this->AddElement(uniqueNodes, etyp, true);
+ else
+ newElem = this->AddElement(uniqueNodes, etyp, false);
+ if (newElem)
+ {
+ myLastCreatedElems.Append(newElem);
+ if ( aShapeId )
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ aMesh->RemoveElement(elem);
}
}
else {
// Remove invalid regular element or invalid polygon
+ //MESSAGE("Remove invalid " << elem->GetID());
rmElemIds.push_back( elem->GetID() );
}
} // loop on elements
- // Remove equal nodes and bad elements
+ // Remove bad elements, then equal nodes (order important)
- Remove( rmNodeIds, true );
Remove( rmElemIds, false );
+ Remove( rmNodeIds, true );
}
-// =================================================
+// ========================================================
// class : SortableElement
-// purpose : auxilary
-// =================================================
+// purpose : allow sorting elements basing on their nodes
+// ========================================================
class SortableElement : public set <const SMDS_MeshElement*>
{
- public:
+public:
SortableElement( const SMDS_MeshElement* theElem )
- {
- myID = theElem->GetID();
- SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
- while ( nodeIt->more() )
- this->insert( nodeIt->next() );
- }
+ {
+ myElem = theElem;
+ SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
+ while ( nodeIt->more() )
+ this->insert( nodeIt->next() );
+ }
- const long GetID() const
- { return myID; }
+ const SMDS_MeshElement* Get() const
+ { return myElem; }
- void SetID(const long anID) const
- { myID = anID; }
+ void Set(const SMDS_MeshElement* e) const
+ { myElem = e; }
- private:
- mutable long myID;
+private:
+ mutable const SMDS_MeshElement* myElem;
};
-
//=======================================================================
-//function : MergeEqualElements
-//purpose : Remove all but one of elements built on the same nodes.
+//function : FindEqualElements
+//purpose : Return list of group of elements built on the same nodes.
+// Search among theElements or in the whole mesh if theElements is empty
//=======================================================================
-
-void SMESH_MeshEditor::MergeEqualElements()
+void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
+ TListOfListOfElementsID & theGroupsOfElementsID)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- SMESHDS_Mesh* aMesh = GetMeshDS();
+ typedef set<const SMDS_MeshElement*> TElemsSet;
+ typedef map< SortableElement, int > TMapOfNodeSet;
+ typedef list<int> TGroupOfElems;
- SMDS_EdgeIteratorPtr eIt = aMesh->edgesIterator();
- SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
- SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
+ TElemsSet elems;
+ if ( theElements.empty() )
+ { // get all elements in the mesh
+ SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
+ while ( eIt->more() )
+ elems.insert( elems.end(), eIt->next());
+ }
+ else
+ elems = theElements;
+
+ vector< TGroupOfElems > arrayOfGroups;
+ TGroupOfElems groupOfElems;
+ TMapOfNodeSet mapOfNodeSet;
+
+ TElemsSet::iterator elemIt = elems.begin();
+ for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
+ const SMDS_MeshElement* curElem = *elemIt;
+ SortableElement SE(curElem);
+ int ind = -1;
+ // check uniqueness
+ pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
+ if( !(pp.second) ) {
+ TMapOfNodeSet::iterator& itSE = pp.first;
+ ind = (*itSE).second;
+ arrayOfGroups[ind].push_back(curElem->GetID());
+ }
+ else {
+ groupOfElems.clear();
+ groupOfElems.push_back(curElem->GetID());
+ arrayOfGroups.push_back(groupOfElems);
+ i++;
+ }
+ }
- list< int > rmElemIds; // IDs of elems to remove
+ vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
+ for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
+ groupOfElems = *groupIt;
+ if ( groupOfElems.size() > 1 ) {
+ groupOfElems.sort();
+ theGroupsOfElementsID.push_back(groupOfElems);
+ }
+ }
+}
- for ( int iDim = 1; iDim <= 3; iDim++ ) {
+//=======================================================================
+//function : MergeElements
+//purpose : In each given group, substitute all elements by the first one.
+//=======================================================================
- set< SortableElement > setOfNodeSet;
- while ( 1 ) {
- // get next element
- const SMDS_MeshElement* elem = 0;
- if ( iDim == 1 ) {
- if ( eIt->more() ) elem = eIt->next();
- } else if ( iDim == 2 ) {
- if ( fIt->more() ) elem = fIt->next();
- } else {
- if ( vIt->more() ) elem = vIt->next();
- }
- if ( !elem ) break;
+void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
- SortableElement SE(elem);
+ typedef list<int> TListOfIDs;
+ TListOfIDs rmElemIds; // IDs of elems to remove
- // check uniqueness
- pair< set<SortableElement>::iterator, bool> pp = setOfNodeSet.insert(SE);
- if( !(pp.second) ) {
- set<SortableElement>::iterator itSE = pp.first;
- SortableElement SEold = *itSE;
- if( SEold.GetID() > SE.GetID() ) {
- rmElemIds.push_back( SEold.GetID() );
- (*itSE).SetID(SE.GetID());
- }
- else {
- rmElemIds.push_back( SE.GetID() );
- }
- }
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
+ while ( groupsIt != theGroupsOfElementsID.end() ) {
+ TListOfIDs& aGroupOfElemID = *groupsIt;
+ aGroupOfElemID.sort();
+ int elemIDToKeep = aGroupOfElemID.front();
+ const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
+ aGroupOfElemID.pop_front();
+ TListOfIDs::iterator idIt = aGroupOfElemID.begin();
+ while ( idIt != aGroupOfElemID.end() ) {
+ int elemIDToRemove = *idIt;
+ const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
+ // add the kept element in groups of removed one (PAL15188)
+ AddToSameGroups( elemToKeep, elemToRemove, aMesh );
+ rmElemIds.push_back( elemIDToRemove );
+ ++idIt;
}
+ ++groupsIt;
}
Remove( rmElemIds, false );
}
+//=======================================================================
+//function : MergeEqualElements
+//purpose : Remove all but one of elements built on the same nodes.
+//=======================================================================
+
+void SMESH_MeshEditor::MergeEqualElements()
+{
+ set<const SMDS_MeshElement*> aMeshElements; /* empty input -
+ to merge equal elements in the whole mesh */
+ TListOfListOfElementsID aGroupsOfElementsID;
+ FindEqualElements(aMeshElements, aGroupsOfElementsID);
+ MergeElements(aGroupsOfElementsID);
+}
+
//=======================================================================
//function : FindFaceInSet
//purpose : Return a face having linked nodes n1 and n2 and which is
// - not in avoidSet,
// - in elemSet provided that !elemSet.empty()
+// i1 and i2 optionally returns indices of n1 and n2
//=======================================================================
const SMDS_MeshElement*
- SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
- const SMDS_MeshNode* n2,
- const map<int,const SMDS_MeshElement*>& elemSet,
- const map<int,const SMDS_MeshElement*>& avoidSet)
+SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ const TIDSortedElemSet& elemSet,
+ const TIDSortedElemSet& avoidSet,
+ int* n1ind,
+ int* n2ind)
{
- SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator();
- while ( invElemIt->more() ) { // loop on inverse elements of n1
+ int i1, i2;
+ const SMDS_MeshElement* face = 0;
+
+ SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
+ //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
+ while ( invElemIt->more() && !face ) // loop on inverse faces of n1
+ {
+ //MESSAGE("in while ( invElemIt->more() && !face )");
const SMDS_MeshElement* elem = invElemIt->next();
- if (elem->GetType() != SMDSAbs_Face ||
- avoidSet.find( elem->GetID() ) != avoidSet.end() )
+ if (avoidSet.count( elem ))
continue;
- if ( !elemSet.empty() && elemSet.find( elem->GetID() ) == elemSet.end())
+ if ( !elemSet.empty() && !elemSet.count( elem ))
continue;
- // get face nodes and find index of n1
- int i1, nbN = elem->NbNodes(), iNode = 0;
- const SMDS_MeshNode* faceNodes[ nbN ], *n;
- SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
- while ( nIt->more() ) {
- faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
- if ( faceNodes[ iNode++ ] == n1 )
- i1 = iNode - 1;
- }
+ // index of n1
+ i1 = elem->GetNodeIndex( n1 );
// find a n2 linked to n1
- if(!elem->IsQuadratic()) {
- for ( iNode = 0; iNode < 2; iNode++ ) {
- if ( iNode ) // node before n1
- n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
- else // node after n1
- n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
- if ( n == n2 )
- return elem;
- }
- }
- else { // analysis for quadratic elements
- bool IsFind = false;
- // check using only corner nodes
- for ( iNode = 0; iNode < 2; iNode++ ) {
- if ( iNode ) // node before n1
- n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
- else // node after n1
- n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
- if ( n == n2 )
- IsFind = true;
- }
- if(IsFind) {
- return elem;
- }
- else {
- // check using all nodes
- const SMDS_QuadraticFaceOfNodes* F =
- static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
- // use special nodes iterator
- iNode = 0;
- SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
- while ( anIter->more() ) {
- faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
- if ( faceNodes[ iNode++ ] == n1 )
- i1 = iNode - 1;
- }
- for ( iNode = 0; iNode < 2; iNode++ ) {
- if ( iNode ) // node before n1
- n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
- else // node after n1
- n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
- if ( n == n2 ) {
- return elem;
- }
+ int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
+ for ( int di = -1; di < 2 && !face; di += 2 )
+ {
+ i2 = (i1+di+nbN) % nbN;
+ if ( elem->GetNode( i2 ) == n2 )
+ face = elem;
+ }
+ if ( !face && elem->IsQuadratic())
+ {
+ // analysis for quadratic elements using all nodes
+ const SMDS_VtkFace* F =
+ dynamic_cast<const SMDS_VtkFace*>(elem);
+ if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
+ // use special nodes iterator
+ SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
+ const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
+ for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
+ {
+ const SMDS_MeshNode* n = cast2Node( anIter->next() );
+ if ( n1 == prevN && n2 == n )
+ {
+ face = elem;
}
+ else if ( n2 == prevN && n1 == n )
+ {
+ face = elem; swap( i1, i2 );
+ }
+ prevN = n;
}
- } // end analysis for quadratic elements
+ }
}
- return 0;
+ if ( n1ind ) *n1ind = i1;
+ if ( n2ind ) *n2ind = i2;
+ return face;
}
//=======================================================================
const SMDS_MeshNode* n2,
const SMDS_MeshElement* elem)
{
- map<int,const SMDS_MeshElement*> elemSet, avoidSet;
+ TIDSortedElemSet elemSet, avoidSet;
if ( elem )
- avoidSet.insert ( make_pair(elem->GetID(),elem) );
+ avoidSet.insert ( elem );
return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
}
//=======================================================================
-//function : findFreeBorder
+//function : FindFreeBorder
//purpose :
//=======================================================================
#define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
-static bool findFreeBorder (const SMDS_MeshNode* theFirstNode,
- const SMDS_MeshNode* theSecondNode,
- const SMDS_MeshNode* theLastNode,
- list< const SMDS_MeshNode* > & theNodes,
- list< const SMDS_MeshElement* > & theFaces)
+bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
+ const SMDS_MeshNode* theSecondNode,
+ const SMDS_MeshNode* theLastNode,
+ list< const SMDS_MeshNode* > & theNodes,
+ list< const SMDS_MeshElement* >& theFaces)
{
if ( !theFirstNode || !theSecondNode )
return false;
//vector<const SMDS_MeshNode*> nodes;
const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
- set < const SMDS_MeshElement* > foundElems;
+ TIDSortedElemSet foundElems;
bool needTheLast = ( theLastNode != 0 );
while ( nStart != theLastNode ) {
list< const SMDS_MeshElement* > curElemList;
list< const SMDS_MeshNode* > nStartList;
- SMDS_ElemIteratorPtr invElemIt = nStart->facesIterator();
+ SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
while ( invElemIt->more() ) {
const SMDS_MeshElement* e = invElemIt->next();
if ( e == curElem || foundElems.insert( e ).second ) {
// get nodes
int iNode = 0, nbNodes = e->NbNodes();
- const SMDS_MeshNode* nodes[nbNodes+1];
+ //const SMDS_MeshNode* nodes[nbNodes+1];
+ vector<const SMDS_MeshNode*> nodes(nbNodes+1);
+
if(e->IsQuadratic()) {
- const SMDS_QuadraticFaceOfNodes* F =
- static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
+ const SMDS_VtkFace* F =
+ dynamic_cast<const SMDS_VtkFace*>(e);
+ if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
// use special nodes iterator
- SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+ SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
while( anIter->more() ) {
- nodes[ iNode++ ] = anIter->next();
+ nodes[ iNode++ ] = cast2Node(anIter->next());
}
}
else {
cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
// find one more free border
- if ( ! findFreeBorder( nIgnore, nStart, theLastNode, *cNL, *cFL )) {
+ if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
cNL->clear();
cFL->clear();
}
{
list< const SMDS_MeshNode* > nodes;
list< const SMDS_MeshElement* > faces;
- return findFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
+ return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
}
//=======================================================================
//=======================================================================
SMESH_MeshEditor::Sew_Error
- SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
- const SMDS_MeshNode* theBordSecondNode,
- const SMDS_MeshNode* theBordLastNode,
- const SMDS_MeshNode* theSideFirstNode,
- const SMDS_MeshNode* theSideSecondNode,
- const SMDS_MeshNode* theSideThirdNode,
- const bool theSideIsFreeBorder,
- const bool toCreatePolygons,
- const bool toCreatePolyedrs)
+SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
+ const SMDS_MeshNode* theBordSecondNode,
+ const SMDS_MeshNode* theBordLastNode,
+ const SMDS_MeshNode* theSideFirstNode,
+ const SMDS_MeshNode* theSideSecondNode,
+ const SMDS_MeshNode* theSideThirdNode,
+ const bool theSideIsFreeBorder,
+ const bool toCreatePolygons,
+ const bool toCreatePolyedrs)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
// Free border 1
// --------------
- if (!findFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
+ if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
nSide[0], eSide[0])) {
MESSAGE(" Free Border 1 not found " );
aResult = SEW_BORDER1_NOT_FOUND;
if (theSideIsFreeBorder) {
// Free border 2
// --------------
- if (!findFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
+ if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
nSide[1], eSide[1])) {
MESSAGE(" Free Border 2 not found " );
aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
// links of the free border
// -------------------------------------------------------------------------
- // 1. Since sewing may brake if there are volumes to split on the side 2,
+ // 1. Since sewing may break if there are volumes to split on the side 2,
// we wont move nodes but just compute new coordinates for them
typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
TNodeXYZMap nBordXYZ;
checkedLinkIDs.clear();
gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
- SMDS_ElemIteratorPtr invElemIt
- = prevSideNode->GetInverseElementIterator();
- while ( invElemIt->more() ) { // loop on inverse elements on the Side 2
+ // loop on inverse elements of current node (prevSideNode) on the Side 2
+ SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
+ while ( invElemIt->more() )
+ {
const SMDS_MeshElement* elem = invElemIt->next();
- // prepare data for a loop on links, of a face or a volume
+ // prepare data for a loop on links coming to prevSideNode, of a face or a volume
int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
- const SMDS_MeshNode* faceNodes[ nbNodes ];
+ vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
bool isVolume = volume.Set( elem );
- const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : faceNodes;
+ const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
if ( isVolume ) // --volume
hasVolumes = true;
- //else if ( nbNodes > 2 ) { // --face
else if ( elem->GetType()==SMDSAbs_Face ) { // --face
// retrieve all face nodes and find iPrevNode - an index of the prevSideNode
if(elem->IsQuadratic()) {
- const SMDS_QuadraticFaceOfNodes* F =
- static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
+ const SMDS_VtkFace* F =
+ dynamic_cast<const SMDS_VtkFace*>(elem);
+ if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
// use special nodes iterator
- SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+ SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
while( anIter->more() ) {
- nodes[ iNode ] = anIter->next();
+ nodes[ iNode ] = cast2Node(anIter->next());
if ( nodes[ iNode++ ] == prevSideNode )
iPrevNode = iNode - 1;
}
else {
SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
while ( nIt->more() ) {
- nodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
+ nodes[ iNode ] = cast2Node( nIt->next() );
if ( nodes[ iNode++ ] == prevSideNode )
iPrevNode = iNode - 1;
}
long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
if (!isJustChecked &&
- foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() ) {
+ foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
+ {
// test a link geometrically
gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
bool linkIsBetter = false;
- double dot, dist;
+ double dot = 0.0, dist = 0.0;
if ( searchByDir ) { // choose most co-directed link
dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
linkIsBetter = ( dot > maxDot );
// find the next border link to compare with
gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
+ // move to next border node if sideNode is before forward border node (bordPos)
while ( *nBordIt != theBordLastNode && !searchByDir ) {
prevBordNode = *nBordIt;
nBordIt++;
TListOfListOfNodes nodeGroupsToMerge;
if ( nbNodes[0] == nbNodes[1] ||
- ( theSideIsFreeBorder && !theSideThirdNode)) {
+ ( theSideIsFreeBorder && !theSideThirdNode)) {
// all nodes are to be merged
{
nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
- nodeGroupsToMerge.back().push_back( *nIt[0] ); // tp remove
+ nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
}
}
else {
// insert new nodes into the border and the side to get equal nb of segments
// get normalized parameters of nodes on the borders
- double param[ 2 ][ maxNbNodes ];
+ //double param[ 2 ][ maxNbNodes ];
+ double* param[ 2 ];
+ param[0] = new double [ maxNbNodes ];
+ param[1] = new double [ maxNbNodes ];
int iNode, iBord;
for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
}
}
+ delete param[0];
+ delete param[1];
} // end: insert new nodes
MergeNodes ( nodeGroupsToMerge );
// find indices of 2 link nodes and of the rest nodes
int iNode = 0, il1, il2, i3, i4;
il1 = il2 = i3 = i4 = -1;
- const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
+ //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
+ vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
if(theFace->IsQuadratic()) {
- const SMDS_QuadraticFaceOfNodes* F =
- static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
+ const SMDS_VtkFace* F =
+ dynamic_cast<const SMDS_VtkFace*>(theFace);
+ if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
// use special nodes iterator
- SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+ SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
while( anIter->more() ) {
- const SMDS_MeshNode* n = anIter->next();
+ const SMDS_MeshNode* n = cast2Node(anIter->next());
if ( n == theBetweenNode1 )
il1 = iNode;
else if ( n == theBetweenNode2 )
bool isFLN = false;
if(theFace->IsQuadratic()) {
- const SMDS_QuadraticFaceOfNodes* F =
- static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
+ const SMDS_VtkFace* F =
+ dynamic_cast<const SMDS_VtkFace*>(theFace);
+ if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
// use special nodes iterator
- SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+ SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
while( anIter->more() && !isFLN ) {
- const SMDS_MeshNode* n = anIter->next();
+ const SMDS_MeshNode* n = cast2Node(anIter->next());
poly_nodes[iNode++] = n;
if (n == nodes[il1]) {
isFLN = true;
}
// add nodes of face starting from last node of link
while ( anIter->more() ) {
- poly_nodes[iNode++] = anIter->next();
+ poly_nodes[iNode++] = cast2Node(anIter->next());
}
}
else {
return;
}
+ SMESHDS_Mesh *aMesh = GetMeshDS();
if( !theFace->IsQuadratic() ) {
// put aNodesToInsert between theBetweenNode1 and theBetweenNode2
int nbLinkNodes = 2 + aNodesToInsert.size();
- const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
+ //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
+ vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
linkNodes[ 0 ] = nodes[ il1 ];
linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
}
}
}
-
+
// create new elements
- SMESHDS_Mesh *aMesh = GetMeshDS();
int aShapeId = FindShape( theFace );
-
+
i1 = 0; i2 = 1;
for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
SMDS_MeshElement* newElem = 0;
if ( aShapeId && newElem )
aMesh->SetMeshElementOnShape( newElem, aShapeId );
}
-
+
// change nodes of theFace
const SMDS_MeshNode* newNodes[ 4 ];
newNodes[ 0 ] = linkNodes[ i1 ];
newNodes[ 1 ] = linkNodes[ i2 ];
newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
newNodes[ 3 ] = nodes[ i4 ];
- aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
- } // end if(!theFace->IsQuadratic())
+ //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
+ const SMDS_MeshElement* newElem = 0;
+ if (iSplit == iBestQuad)
+ newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
+ else
+ newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
+ myLastCreatedElems.Append(newElem);
+ if ( aShapeId && newElem )
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+} // end if(!theFace->IsQuadratic())
else { // theFace is quadratic
// we have to split theFace on simple triangles and one simple quadrangle
int tmp = il1/2;
il1 = il1 - nbshift;
// now have to insert nodes between n0 and n1 or n1 and n2 (see below)
// n0 n1 n2 n0 n1 n2
- // +-----+-----+ +-----+-----+
+ // +-----+-----+ +-----+-----+
// \ / | |
// \ / | |
// n5+ +n3 n7+ +n3
// n4 n6 n5 n4
// create new elements
- SMESHDS_Mesh *aMesh = GetMeshDS();
int aShapeId = FindShape( theFace );
int n1,n2,n3;
}
// create needed triangles using n1,n2,n3 and inserted nodes
int nbn = 2 + aNodesToInsert.size();
- const SMDS_MeshNode* aNodes[nbn];
+ //const SMDS_MeshNode* aNodes[nbn];
+ vector<const SMDS_MeshNode*> aNodes(nbn);
aNodes[0] = nodes[n1];
aNodes[nbn-1] = nodes[n2];
list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
if ( aShapeId && newElem )
aMesh->SetMeshElementOnShape( newElem, aShapeId );
}
- // remove old quadratic face
- aMesh->RemoveElement(theFace);
}
+ // remove old face
+ aMesh->RemoveElement(theFace);
}
//=======================================================================
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator();
+ SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
const SMDS_MeshElement* elem = invElemIt->next();
- if (elem->GetType() != SMDSAbs_Volume)
- continue;
// check, if current volume has link theBetweenNode1 - theBetweenNode2
SMDS_VolumeTool aVolume (elem);
}
//=======================================================================
-//function : ConvertElemToQuadratic
-//purpose :
+/*!
+ * \brief Convert elements contained in a submesh to quadratic
+ * \retval int - nb of checked elements
+ */
//=======================================================================
-void SMESH_MeshEditor::ConvertElemToQuadratic(SMESHDS_SubMesh *theSm,
- SMESH_MesherHelper* theHelper,
- const bool theForce3d)
+
+int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
+ SMESH_MesherHelper& theHelper,
+ const bool theForce3d)
{
- if( !theSm ) return;
- SMESHDS_Mesh* meshDS = GetMeshDS();
+ int nbElem = 0;
+ if( !theSm ) return nbElem;
+
+ vector<int> nbNodeInFaces;
SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
while(ElemItr->more())
{
+ nbElem++;
const SMDS_MeshElement* elem = ElemItr->next();
- if( !elem ) continue;
+ if( !elem || elem->IsQuadratic() ) continue;
int id = elem->GetID();
+ //MESSAGE("elem " << id);
+ id = 0; // get a free number for new elements
int nbNodes = elem->NbNodes();
- vector<const SMDS_MeshNode *> aNds (nbNodes);
-
- for(int i = 0; i < nbNodes; i++)
- {
- aNds[i] = elem->GetNode(i);
- }
-
SMDSAbs_ElementType aType = elem->GetType();
+
+ vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
+ if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
+ nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
+
const SMDS_MeshElement* NewElem = 0;
switch( aType )
{
case SMDSAbs_Edge :
- {
- meshDS->RemoveFreeElement(elem, theSm);
- NewElem = theHelper->AddQuadraticEdge(aNds[0], aNds[1], id, theForce3d);
- break;
- }
+ {
+ NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
+ break;
+ }
case SMDSAbs_Face :
- {
- if(elem->IsQuadratic()) continue;
-
- meshDS->RemoveFreeElement(elem, theSm);
- switch(nbNodes)
{
- case 3:
- NewElem = theHelper->AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
- break;
- case 4:
- NewElem = theHelper->AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
- break;
- default:
- continue;
+ switch(nbNodes)
+ {
+ case 3:
+ NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
+ break;
+ case 4:
+ NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+ break;
+ default:
+ NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
+ continue;
+ }
+ break;
}
- break;
- }
case SMDSAbs_Volume :
- {
- if( elem->IsQuadratic() ) continue;
-
- meshDS->RemoveFreeElement(elem, theSm);
- switch(nbNodes)
{
- case 4:
- NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, true);
- break;
- case 6:
- NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, true);
- break;
- case 8:
- NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
- aNds[4], aNds[5], aNds[6], aNds[7], id, true);
- break;
- default:
- continue;
+ switch(nbNodes)
+ {
+ case 4:
+ NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+ break;
+ case 5:
+ NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
+ break;
+ case 6:
+ NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
+ break;
+ case 8:
+ NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
+ break;
+ default:
+ NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
+ }
+ break;
}
- break;
- }
default :
continue;
}
+ ReplaceElemInGroups( elem, NewElem, GetMeshDS());
if( NewElem )
- {
- AddToSameGroups( NewElem, elem, meshDS);
theSm->AddElement( NewElem );
- }
+
+ GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
}
+// if (!GetMeshDS()->isCompacted())
+// GetMeshDS()->compactMesh();
+ return nbElem;
}
//=======================================================================
{
SMESHDS_Mesh* meshDS = GetMeshDS();
- SMESH_MesherHelper* aHelper = new SMESH_MesherHelper(*myMesh);
- aHelper->SetKeyIsQuadratic( true );
- const TopoDS_Shape& aShape = meshDS->ShapeToMesh();
+ SMESH_MesherHelper aHelper(*myMesh);
+ aHelper.SetIsQuadratic( true );
- if ( !aShape.IsNull() && GetMesh()->GetSubMeshContaining(aShape) )
+ int nbCheckedElems = 0;
+ if ( myMesh->HasShapeToMesh() )
{
- SMESH_subMesh *aSubMesh = GetMesh()->GetSubMeshContaining(aShape);
-
- const map < int, SMESH_subMesh * >& aMapSM = aSubMesh->DependsOn();
- map < int, SMESH_subMesh * >::const_iterator itsub;
- for (itsub = aMapSM.begin(); itsub != aMapSM.end(); itsub++)
+ if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
{
- SMESHDS_SubMesh *sm = ((*itsub).second)->GetSubMeshDS();
- aHelper->SetSubShape( (*itsub).second->GetSubShape() );
- ConvertElemToQuadratic(sm, aHelper, theForce3d);
+ SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
+ while ( smIt->more() ) {
+ SMESH_subMesh* sm = smIt->next();
+ if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
+ aHelper.SetSubShape( sm->GetSubShape() );
+ nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
+ }
+ }
}
- aHelper->SetSubShape( aSubMesh->GetSubShape() );
- ConvertElemToQuadratic(aSubMesh->GetSubMeshDS(), aHelper, theForce3d);
}
- else
+ int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
+ if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
{
+ SMESHDS_SubMesh *smDS = 0;
SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
while(aEdgeItr->more())
{
const SMDS_MeshEdge* edge = aEdgeItr->next();
- if(edge)
+ if(edge && !edge->IsQuadratic())
{
- int id = edge->GetID();
- const SMDS_MeshNode* n1 = edge->GetNode(0);
- const SMDS_MeshNode* n2 = edge->GetNode(1);
+ int id = edge->GetID();
+ //MESSAGE("edge->GetID() " << id);
+ const SMDS_MeshNode* n1 = edge->GetNode(0);
+ const SMDS_MeshNode* n2 = edge->GetNode(1);
- RemoveElemFromGroups (edge, meshDS);
- meshDS->SMDS_Mesh::RemoveFreeElement(edge);
+ meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
- const SMDS_QuadraticEdge* NewEdge = aHelper->AddQuadraticEdge(n1, n2, id, theForce3d);
- AddToSameGroups(NewEdge, edge, meshDS);
+ const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
+ ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
}
}
SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
{
const SMDS_MeshFace* face = aFaceItr->next();
if(!face || face->IsQuadratic() ) continue;
-
+
int id = face->GetID();
int nbNodes = face->NbNodes();
- vector<const SMDS_MeshNode *> aNds (nbNodes);
-
- for(int i = 0; i < nbNodes; i++)
- {
- aNds[i] = face->GetNode(i);
- }
+ vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
- RemoveElemFromGroups (face, meshDS);
- meshDS->SMDS_Mesh::RemoveFreeElement(face);
+ meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
SMDS_MeshFace * NewFace = 0;
switch(nbNodes)
{
case 3:
- NewFace = aHelper->AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
- break;
+ NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
+ break;
case 4:
- NewFace = aHelper->AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
- break;
+ NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+ break;
default:
- continue;
+ NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
}
- AddToSameGroups(NewFace, face, meshDS);
+ ReplaceElemInGroups( face, NewFace, GetMeshDS());
}
+ vector<int> nbNodeInFaces;
SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
while(aVolumeItr->more())
{
const SMDS_MeshVolume* volume = aVolumeItr->next();
if(!volume || volume->IsQuadratic() ) continue;
-
+
int id = volume->GetID();
int nbNodes = volume->NbNodes();
- vector<const SMDS_MeshNode *> aNds (nbNodes);
-
- for(int i = 0; i < nbNodes; i++)
- {
- aNds[i] = volume->GetNode(i);
- }
+ vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
+ if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
+ nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
- RemoveElemFromGroups (volume, meshDS);
- meshDS->SMDS_Mesh::RemoveFreeElement(volume);
+ meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
SMDS_MeshVolume * NewVolume = 0;
switch(nbNodes)
{
case 4:
- NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2],
- aNds[3], id, true );
- break;
+ NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
+ nodes[3], id, theForce3d );
+ break;
+ case 5:
+ NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
+ nodes[3], nodes[4], id, theForce3d);
+ break;
case 6:
- NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2],
- aNds[3], aNds[4], aNds[5], id, true);
- break;
+ NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
+ nodes[3], nodes[4], nodes[5], id, theForce3d);
+ break;
case 8:
- NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
- aNds[4], aNds[5], aNds[6], aNds[7], id, true);
- break;
+ NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
+ break;
default:
- continue;
+ NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
}
- AddToSameGroups(NewVolume, volume, meshDS);
+ ReplaceElemInGroups(volume, NewVolume, meshDS);
}
}
- delete aHelper;
+
+ if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
+ { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
+ aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+ aHelper.FixQuadraticElements();
+ }
+ if (!GetMeshDS()->isCompacted())
+ GetMeshDS()->compactMesh();
}
//=======================================================================
-//function : RemoveQuadElem
-//purpose :
+/*!
+ * \brief Convert quadratic elements to linear ones and remove quadratic nodes
+ * \retval int - nb of checked elements
+ */
//=======================================================================
-void SMESH_MeshEditor::RemoveQuadElem(SMESHDS_SubMesh *theSm,
- SMDS_ElemIteratorPtr theItr,
- RemoveQuadNodeMap& theRemoveNodeMap)
+
+int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
+ SMDS_ElemIteratorPtr theItr,
+ const int theShapeID)
{
+ int nbElem = 0;
SMESHDS_Mesh* meshDS = GetMeshDS();
+ const bool notFromGroups = false;
+
while( theItr->more() )
{
const SMDS_MeshElement* elem = theItr->next();
- if( elem )
+ nbElem++;
+ if( elem && elem->IsQuadratic())
{
- if( !elem->IsQuadratic() )
- continue;
-
int id = elem->GetID();
-
- int nbNodes = elem->NbNodes(), idx = 0;
- vector<const SMDS_MeshNode *> aNds;
+ int nbNodes = elem->NbNodes();
+ vector<const SMDS_MeshNode *> nodes, mediumNodes;
+ nodes.reserve( nbNodes );
+ mediumNodes.reserve( nbNodes );
for(int i = 0; i < nbNodes; i++)
{
- const SMDS_MeshNode* n = elem->GetNode(i);
-
- if( elem->IsMediumNode( n ) )
- {
- ItRemoveQuadNodeMap itRNM = theRemoveNodeMap.find( n );
- if( itRNM == theRemoveNodeMap.end() )
- {
- theRemoveNodeMap.insert(RemoveQuadNodeMap::value_type( n,theSm ));
- }
- }
- else
- aNds.push_back( n );
- }
-
- idx = aNds.size();
- if( !idx ) continue;
- SMDSAbs_ElementType aType = elem->GetType();
+ const SMDS_MeshNode* n = elem->GetNode(i);
- //remove old quadratic elements
- meshDS->RemoveFreeElement( elem, theSm );
-
- SMDS_MeshElement * NewElem = 0;
- switch(aType)
- {
- case SMDSAbs_Edge:
- NewElem = meshDS->AddEdgeWithID( aNds[0], aNds[1] ,id );
- break;
- case SMDSAbs_Face:
- if( idx==3 ) NewElem = meshDS->AddFaceWithID( aNds[0],
- aNds[1], aNds[2], id );
- if( idx==4 ) NewElem = meshDS->AddFaceWithID( aNds[0],
- aNds[1], aNds[2], aNds[3],id );
- break;
- case SMDSAbs_Volume:
- if( idx==4 ) NewElem = meshDS->AddVolumeWithID( aNds[0],
- aNds[1], aNds[2], aNds[3], id );
- if( idx==6 ) NewElem = meshDS->AddVolumeWithID( aNds[0],
- aNds[1], aNds[2], aNds[3],
- aNds[4], aNds[5], id );
- if( idx==8 ) NewElem = meshDS->AddVolumeWithID(aNds[0],
- aNds[1], aNds[2], aNds[3],
- aNds[4], aNds[5], aNds[6],
- aNds[7] ,id );
- break;
- default:
- break;
- }
-
- AddToSameGroups(NewElem, elem, meshDS);
- if( theSm )
- theSm->AddElement( NewElem );
+ if( elem->IsMediumNode( n ) )
+ mediumNodes.push_back( n );
+ else
+ nodes.push_back( n );
+ }
+ if( nodes.empty() ) continue;
+ SMDSAbs_ElementType aType = elem->GetType();
+
+ //remove old quadratic element
+ meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
+
+ SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
+ ReplaceElemInGroups(elem, NewElem, meshDS);
+ if( theSm && NewElem )
+ theSm->AddElement( NewElem );
+
+ // remove medium nodes
+ vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
+ for ( ; nIt != mediumNodes.end(); ++nIt ) {
+ const SMDS_MeshNode* n = *nIt;
+ if ( n->NbInverseElements() == 0 ) {
+ if ( n->getshapeId() != theShapeID )
+ meshDS->RemoveFreeNode( n, meshDS->MeshElements
+ ( n->getshapeId() ));
+ else
+ meshDS->RemoveFreeNode( n, theSm );
+ }
+ }
}
}
+ return nbElem;
}
+
//=======================================================================
//function : ConvertFromQuadratic
//purpose :
//=======================================================================
bool SMESH_MeshEditor::ConvertFromQuadratic()
{
- SMESHDS_Mesh* meshDS = GetMeshDS();
- RemoveQuadNodeMap aRemoveNodeMap;
-
- const TopoDS_Shape& aShape = meshDS->ShapeToMesh();
-
- if ( !aShape.IsNull() && GetMesh()->GetSubMeshContaining(aShape) )
+ int nbCheckedElems = 0;
+ if ( myMesh->HasShapeToMesh() )
{
- SMESH_subMesh *aSubMesh = GetMesh()->GetSubMeshContaining(aShape);
-
- const map < int, SMESH_subMesh * >& aMapSM = aSubMesh->DependsOn();
- map < int, SMESH_subMesh * >::const_iterator itsub;
- for (itsub = aMapSM.begin(); itsub != aMapSM.end(); itsub++)
+ if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
{
- SMESHDS_SubMesh *sm = ((*itsub).second)->GetSubMeshDS();
- if( sm )
- RemoveQuadElem( sm, sm->GetElements(), aRemoveNodeMap );
+ SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
+ while ( smIt->more() ) {
+ SMESH_subMesh* sm = smIt->next();
+ if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
+ nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
+ }
}
- SMESHDS_SubMesh *Sm = aSubMesh->GetSubMeshDS();
- if( Sm )
- RemoveQuadElem( Sm, Sm->GetElements(), aRemoveNodeMap );
- }
- else
- {
- SMESHDS_SubMesh *aSM = 0;
- RemoveQuadElem( aSM, meshDS->elementsIterator(), aRemoveNodeMap );
}
- //remove all quadratic nodes
- ItRemoveQuadNodeMap itRNM = aRemoveNodeMap.begin();
- for ( ; itRNM != aRemoveNodeMap.end(); itRNM++ )
+ int totalNbElems =
+ GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
+ if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
{
- meshDS->RemoveFreeNode( (*itRNM).first, (*itRNM).second );
+ SMESHDS_SubMesh *aSM = 0;
+ removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
}
return true;
//=======================================================================
SMESH_MeshEditor::Sew_Error
- SMESH_MeshEditor::SewSideElements (map<int,const SMDS_MeshElement*>& theSide1,
- map<int,const SMDS_MeshElement*>& theSide2,
- const SMDS_MeshNode* theFirstNode1,
- const SMDS_MeshNode* theFirstNode2,
- const SMDS_MeshNode* theSecondNode1,
- const SMDS_MeshNode* theSecondNode2)
+SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
+ TIDSortedElemSet& theSide2,
+ const SMDS_MeshNode* theFirstNode1,
+ const SMDS_MeshNode* theFirstNode2,
+ const SMDS_MeshNode* theSecondNode1,
+ const SMDS_MeshNode* theSecondNode2)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
// 1. Build set of faces representing each side:
// =======================================================================
// a. build set of nodes belonging to faces
- // b. complete set of faces: find missing fices whose nodes are in set of nodes
+ // b. complete set of faces: find missing faces whose nodes are in set of nodes
// c. create temporary faces representing side of volumes if correspondent
// face does not exist
SMESHDS_Mesh* aMesh = GetMeshDS();
- SMDS_Mesh aTmpFacesMesh;
+ // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
+ //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
set<const SMDS_MeshElement*> faceSet1, faceSet2;
set<const SMDS_MeshElement*> volSet1, volSet2;
set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
- map<int,const SMDS_MeshElement*> * elemSetPtr[] = { &theSide1, &theSide2 };
+ TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
int iSide, iFace, iNode;
+ list<const SMDS_MeshElement* > tempFaceList;
for ( iSide = 0; iSide < 2; iSide++ ) {
set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
- map<int,const SMDS_MeshElement*> * elemSet = elemSetPtr[ iSide ];
+ TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
set<const SMDS_MeshElement*>::iterator vIt;
- map<int,const SMDS_MeshElement*>::iterator eIt;
+ TIDSortedElemSet::iterator eIt;
set<const SMDS_MeshNode*>::iterator nIt;
// check that given nodes belong to given elements
const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
int firstIndex = -1, secondIndex = -1;
for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
- const SMDS_MeshElement* elem = (*eIt).second;
+ const SMDS_MeshElement* elem = *eIt;
if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
if ( firstIndex > -1 && secondIndex > -1 ) break;
// -----------------------------------------------------------
// 1a. Collect nodes of existing faces
// and build set of face nodes in order to detect missing
- // faces corresponing to sides of volumes
+ // faces corresponding to sides of volumes
// -----------------------------------------------------------
set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
// loop on the given element of a side
for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
//const SMDS_MeshElement* elem = *eIt;
- const SMDS_MeshElement* elem = (*eIt).second;
+ const SMDS_MeshElement* elem = *eIt;
if ( elem->GetType() == SMDSAbs_Face ) {
faceSet->insert( elem );
set <const SMDS_MeshNode*> faceNodeSet;
volSet->insert( elem );
}
// ------------------------------------------------------------------------------
- // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
+ // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
// ------------------------------------------------------------------------------
for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
- SMDS_ElemIteratorPtr fIt = (*nIt)->facesIterator();
+ SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
while ( fIt->more() ) { // loop on faces sharing a node
const SMDS_MeshElement* f = fIt->next();
if ( faceSet->find( f ) == faceSet->end() ) {
if ( !aFreeFace ) {
// create a temporary face
if ( nbNodes == 3 ) {
- aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
+ //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
+ aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
}
else if ( nbNodes == 4 ) {
- aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
+ //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
+ aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
}
else {
vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
- aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
+ //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
+ aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
}
}
- if ( aFreeFace )
+ if ( aFreeFace ) {
freeFaceList.push_back( aFreeFace );
+ tempFaceList.push_back( aFreeFace );
+ }
} // loop on faces of a volume
const SMDS_MeshElement* e = invElemIt->next();
if ( faceSet->find( e ) != faceSet->end() )
nbSharedNodes++;
- if ( elemSet->find( e->GetID() ) != elemSet->end() )
+ if ( elemSet->find( e ) != elemSet->end() )
nbSharedNodes++;
}
}
fIt++;
}
else
- freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
+ freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
}
if ( freeFaceList.size() > 1 )
{
// choose a face most close to the bary center of the opposite side
gp_XYZ aBC( 0., 0., 0. );
set <const SMDS_MeshNode*> addedNodes;
- map<int,const SMDS_MeshElement*> * elemSet2 = elemSetPtr[ 1 - iSide ];
+ TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
eIt = elemSet2->begin();
for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
- SMDS_ElemIteratorPtr nodeIt = (*eIt).second->nodesIterator();
+ SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
while ( nodeIt->more() ) { // loop on free face nodes
const SMDS_MeshNode* n =
static_cast<const SMDS_MeshNode*>( nodeIt->next() );
const SMDS_MeshElement* aFreeFace = freeFaceList.front();
faceSet->insert( aFreeFace );
// complete a node set with nodes of a found free face
-// for ( iNode = 0; iNode < ; iNode++ )
-// nodeSet->insert( fNodes[ iNode ] );
+ // for ( iNode = 0; iNode < ; iNode++ )
+ // nodeSet->insert( fNodes[ iNode ] );
}
} // loop on volumes of a side
-// // complete a set of faces if new nodes in a nodeSet appeared
-// // ----------------------------------------------------------
-// if ( nodeSetSize != nodeSet->size() ) {
-// for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
-// SMDS_ElemIteratorPtr fIt = (*nIt)->facesIterator();
-// while ( fIt->more() ) { // loop on faces sharing a node
-// const SMDS_MeshElement* f = fIt->next();
-// if ( faceSet->find( f ) == faceSet->end() ) {
-// // check if all nodes are in nodeSet and
-// // complete setOfFaceNodeSet if they are
-// set <const SMDS_MeshNode*> faceNodeSet;
-// SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
-// bool allInSet = true;
-// while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
-// const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
-// if ( nodeSet->find( n ) == nodeSet->end() )
-// allInSet = false;
-// else
-// faceNodeSet.insert( n );
-// }
-// if ( allInSet ) {
-// faceSet->insert( f );
-// setOfFaceNodeSet.insert( faceNodeSet );
-// }
-// }
-// }
-// }
-// }
+ // // complete a set of faces if new nodes in a nodeSet appeared
+ // // ----------------------------------------------------------
+ // if ( nodeSetSize != nodeSet->size() ) {
+ // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
+ // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
+ // while ( fIt->more() ) { // loop on faces sharing a node
+ // const SMDS_MeshElement* f = fIt->next();
+ // if ( faceSet->find( f ) == faceSet->end() ) {
+ // // check if all nodes are in nodeSet and
+ // // complete setOfFaceNodeSet if they are
+ // set <const SMDS_MeshNode*> faceNodeSet;
+ // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
+ // bool allInSet = true;
+ // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
+ // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+ // if ( nodeSet->find( n ) == nodeSet->end() )
+ // allInSet = false;
+ // else
+ // faceNodeSet.insert( n );
+ // }
+ // if ( allInSet ) {
+ // faceSet->insert( f );
+ // setOfFaceNodeSet.insert( faceNodeSet );
+ // }
+ // }
+ // }
+ // }
+ // }
} // Create temporary faces, if there are volumes given
} // loop on sides
if ( faceSet1.size() != faceSet2.size() ) {
// delete temporary faces: they are in reverseElements of actual nodes
- SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
- while ( tmpFaceIt->more() )
- aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+// SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
+// while ( tmpFaceIt->more() )
+// aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+// list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
+// for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
+// aMesh->RemoveElement(*tmpFaceIt);
MESSAGE("Diff nb of faces");
return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
}
set< long > linkIdSet; // links to process
linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
- typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > TPairOfNodes;
- list< TPairOfNodes > linkList[2];
- linkList[0].push_back( TPairOfNodes( theFirstNode1, theSecondNode1 ));
- linkList[1].push_back( TPairOfNodes( theFirstNode2, theSecondNode2 ));
+ typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
+ list< NLink > linkList[2];
+ linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
+ linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
// loop on links in linkList; find faces by links and append links
// of the found faces to linkList
- list< TPairOfNodes >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
+ list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
- TPairOfNodes link[] = { *linkIt[0], *linkIt[1] };
+ NLink link[] = { *linkIt[0], *linkIt[1] };
long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
if ( linkIdSet.find( linkID ) == linkIdSet.end() )
continue;
set< const SMDS_MeshElement* > fMap;
for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
- SMDS_ElemIteratorPtr fIt = n->facesIterator();
+ SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
while ( fIt->more() ) { // loop on faces sharing a node
const SMDS_MeshElement* f = fIt->next();
if (faceSet->find( f ) != faceSet->end() && // f is in face set
nbl++;
if(iSide==0)
notLinkNodes1[nbl] = n;
- //notLinkNodes1.push_back(n);
+ //notLinkNodes1.push_back(n);
else
notLinkNodes2[nbl] = n;
- //notLinkNodes2.push_back(n);
+ //notLinkNodes2.push_back(n);
}
//faceNodes[ iSide ][ iNode++ ] = n;
if(iSide==0) {
}
}
else { // f->IsQuadratic()
- const SMDS_QuadraticFaceOfNodes* F =
- static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
+ const SMDS_VtkFace* F =
+ dynamic_cast<const SMDS_VtkFace*>(f);
+ if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
// use special nodes iterator
- SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+ SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
while ( anIter->more() ) {
const SMDS_MeshNode* n =
static_cast<const SMDS_MeshNode*>( anIter->next() );
}
}
- // check similarity of elements of the sides
- if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
- MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
- if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
- aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
- }
- else {
- aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+ // check similarity of elements of the sides
+ if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
+ MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
+ if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
+ aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
+ }
+ else {
+ aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+ }
+ break; // do not return because it s necessary to remove tmp faces
+ }
+
+ // set nodes to merge
+ // -------------------
+
+ if ( face[0] && face[1] ) {
+ int nbNodes = face[0]->NbNodes();
+ if ( nbNodes != face[1]->NbNodes() ) {
+ MESSAGE("Diff nb of face nodes");
+ aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+ break; // do not return because it s necessary to remove tmp faces
+ }
+ bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
+ if ( nbNodes == 3 ) {
+ //nReplaceMap.insert( TNodeNodeMap::value_type
+ // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
+ nReplaceMap.insert( TNodeNodeMap::value_type
+ ( notLinkNodes1[0], notLinkNodes2[0] ));
+ }
+ else {
+ for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
+ // analyse link orientation in faces
+ int i1 = iLinkNode[ iSide ][ 0 ];
+ int i2 = iLinkNode[ iSide ][ 1 ];
+ reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
+ // if notLinkNodes are the first and the last ones, then
+ // their order does not correspond to the link orientation
+ if (( i1 == 1 && i2 == 2 ) ||
+ ( i1 == 2 && i2 == 1 ))
+ reverse[ iSide ] = !reverse[ iSide ];
+ }
+ if ( reverse[0] == reverse[1] ) {
+ //nReplaceMap.insert( TNodeNodeMap::value_type
+ // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
+ //nReplaceMap.insert( TNodeNodeMap::value_type
+ // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
+ for(int nn=0; nn<nbNodes-2; nn++) {
+ nReplaceMap.insert( TNodeNodeMap::value_type
+ ( notLinkNodes1[nn], notLinkNodes2[nn] ));
+ }
+ }
+ else {
+ //nReplaceMap.insert( TNodeNodeMap::value_type
+ // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
+ //nReplaceMap.insert( TNodeNodeMap::value_type
+ // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
+ for(int nn=0; nn<nbNodes-2; nn++) {
+ nReplaceMap.insert( TNodeNodeMap::value_type
+ ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
+ }
+ }
+ }
+
+ // add other links of the faces to linkList
+ // -----------------------------------------
+
+ //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
+ for ( iNode = 0; iNode < nbNodes; iNode++ ) {
+ //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
+ linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
+ pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
+ if ( !iter_isnew.second ) { // already in a set: no need to process
+ linkIdSet.erase( iter_isnew.first );
+ }
+ else // new in set == encountered for the first time: add
+ {
+ //const SMDS_MeshNode* n1 = nodes[ iNode ];
+ //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
+ const SMDS_MeshNode* n1 = fnodes1[ iNode ];
+ const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
+ linkList[0].push_back ( NLink( n1, n2 ));
+ linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
+ }
+ }
+ } // 2 faces found
+ } // loop on link lists
+
+ if ( aResult == SEW_OK &&
+ ( linkIt[0] != linkList[0].end() ||
+ !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
+ MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
+ " " << (faceSetPtr[1]->empty()));
+ aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+ }
+
+ // ====================================================================
+ // 3. Replace nodes in elements of the side 1 and remove replaced nodes
+ // ====================================================================
+
+ // delete temporary faces: they are in reverseElements of actual nodes
+// SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
+// while ( tmpFaceIt->more() )
+// aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+// list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
+// for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
+// aMesh->RemoveElement(*tmpFaceIt);
+
+ if ( aResult != SEW_OK)
+ return aResult;
+
+ list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
+ // loop on nodes replacement map
+ TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
+ for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
+ if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
+ const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
+ nodeIDsToRemove.push_back( nToRemove->GetID() );
+ // loop on elements sharing nToRemove
+ SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
+ while ( invElemIt->more() ) {
+ const SMDS_MeshElement* e = invElemIt->next();
+ // get a new suite of nodes: make replacement
+ int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
+ vector< const SMDS_MeshNode*> nodes( nbNodes );
+ SMDS_ElemIteratorPtr nIt = e->nodesIterator();
+ while ( nIt->more() ) {
+ const SMDS_MeshNode* n =
+ static_cast<const SMDS_MeshNode*>( nIt->next() );
+ nnIt = nReplaceMap.find( n );
+ if ( nnIt != nReplaceMap.end() ) {
+ nbReplaced++;
+ n = (*nnIt).second;
+ }
+ nodes[ i++ ] = n;
+ }
+ // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
+ // elemIDsToRemove.push_back( e->GetID() );
+ // else
+ if ( nbReplaced )
+ {
+ SMDSAbs_ElementType etyp = e->GetType();
+ SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
+ if (newElem)
+ {
+ myLastCreatedElems.Append(newElem);
+ AddToSameGroups(newElem, e, aMesh);
+ int aShapeId = e->getshapeId();
+ if ( aShapeId )
+ {
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ }
+ aMesh->RemoveElement(e);
+ }
+ }
+ }
+
+ Remove( nodeIDsToRemove, true );
+
+ return aResult;
+}
+
+//================================================================================
+/*!
+ * \brief Find corresponding nodes in two sets of faces
+ * \param theSide1 - first face set
+ * \param theSide2 - second first face
+ * \param theFirstNode1 - a boundary node of set 1
+ * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
+ * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
+ * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
+ * \param nReplaceMap - output map of corresponding nodes
+ * \retval bool - is a success or not
+ */
+//================================================================================
+
+#ifdef _DEBUG_
+//#define DEBUG_MATCHING_NODES
+#endif
+
+SMESH_MeshEditor::Sew_Error
+SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
+ set<const SMDS_MeshElement*>& theSide2,
+ const SMDS_MeshNode* theFirstNode1,
+ const SMDS_MeshNode* theFirstNode2,
+ const SMDS_MeshNode* theSecondNode1,
+ const SMDS_MeshNode* theSecondNode2,
+ TNodeNodeMap & nReplaceMap)
+{
+ set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
+
+ nReplaceMap.clear();
+ if ( theFirstNode1 != theFirstNode2 )
+ nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
+ if ( theSecondNode1 != theSecondNode2 )
+ nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
+
+ set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
+ linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
+
+ list< NLink > linkList[2];
+ linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
+ linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
+
+ // loop on links in linkList; find faces by links and append links
+ // of the found faces to linkList
+ list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
+ for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
+ NLink link[] = { *linkIt[0], *linkIt[1] };
+ if ( linkSet.find( link[0] ) == linkSet.end() )
+ continue;
+
+ // by links, find faces in the face sets,
+ // and find indices of link nodes in the found faces;
+ // in a face set, there is only one or no face sharing a link
+ // ---------------------------------------------------------------
+
+ const SMDS_MeshElement* face[] = { 0, 0 };
+ list<const SMDS_MeshNode*> notLinkNodes[2];
+ //bool reverse[] = { false, false }; // order of notLinkNodes
+ int nbNodes[2];
+ for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
+ {
+ const SMDS_MeshNode* n1 = link[iSide].first;
+ const SMDS_MeshNode* n2 = link[iSide].second;
+ set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
+ set< const SMDS_MeshElement* > facesOfNode1;
+ for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
+ {
+ // during a loop of the first node, we find all faces around n1,
+ // during a loop of the second node, we find one face sharing both n1 and n2
+ const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
+ SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
+ while ( fIt->more() ) { // loop on faces sharing a node
+ const SMDS_MeshElement* f = fIt->next();
+ if (faceSet->find( f ) != faceSet->end() && // f is in face set
+ ! facesOfNode1.insert( f ).second ) // f encounters twice
+ {
+ if ( face[ iSide ] ) {
+ MESSAGE( "2 faces per link " );
+ return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
+ }
+ face[ iSide ] = f;
+ faceSet->erase( f );
+
+ // get not link nodes
+ int nbN = f->NbNodes();
+ if ( f->IsQuadratic() )
+ nbN /= 2;
+ nbNodes[ iSide ] = nbN;
+ list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
+ int i1 = f->GetNodeIndex( n1 );
+ int i2 = f->GetNodeIndex( n2 );
+ int iEnd = nbN, iBeg = -1, iDelta = 1;
+ bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
+ if ( reverse ) {
+ std::swap( iEnd, iBeg ); iDelta = -1;
+ }
+ int i = i2;
+ while ( true ) {
+ i += iDelta;
+ if ( i == iEnd ) i = iBeg + iDelta;
+ if ( i == i1 ) break;
+ nodes.push_back ( f->GetNode( i ) );
+ }
+ }
+ }
+ }
+ }
+ // check similarity of elements of the sides
+ if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
+ MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
+ if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
+ return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
+ }
+ else {
+ return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+ }
+ }
+
+ // set nodes to merge
+ // -------------------
+
+ if ( face[0] && face[1] ) {
+ if ( nbNodes[0] != nbNodes[1] ) {
+ MESSAGE("Diff nb of face nodes");
+ return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+ }
+#ifdef DEBUG_MATCHING_NODES
+ MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
+ << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
+ << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
+#endif
+ int nbN = nbNodes[0];
+ {
+ list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
+ list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
+ for ( int i = 0 ; i < nbN - 2; ++i ) {
+#ifdef DEBUG_MATCHING_NODES
+ MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
+#endif
+ nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
+ }
+ }
+
+ // add other links of the face 1 to linkList
+ // -----------------------------------------
+
+ const SMDS_MeshElement* f0 = face[0];
+ const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
+ for ( int i = 0; i < nbN; i++ )
+ {
+ const SMDS_MeshNode* n2 = f0->GetNode( i );
+ pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
+ linkSet.insert( SMESH_TLink( n1, n2 ));
+ if ( !iter_isnew.second ) { // already in a set: no need to process
+ linkSet.erase( iter_isnew.first );
+ }
+ else // new in set == encountered for the first time: add
+ {
+#ifdef DEBUG_MATCHING_NODES
+ MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
+ << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
+#endif
+ linkList[0].push_back ( NLink( n1, n2 ));
+ linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
+ }
+ n1 = n2;
+ }
+ } // 2 faces found
+ } // loop on link lists
+
+ return SEW_OK;
+}
+
+//================================================================================
+/*!
+ \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+ \param theElems - the list of elements (edges or faces) to be replicated
+ The nodes for duplication could be found from these elements
+ \param theNodesNot - list of nodes to NOT replicate
+ \param theAffectedElems - the list of elements (cells and edges) to which the
+ replicated nodes should be associated to.
+ \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+//================================================================================
+
+bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
+ const TIDSortedElemSet& theNodesNot,
+ const TIDSortedElemSet& theAffectedElems )
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ if ( theElems.size() == 0 )
+ return false;
+
+ SMESHDS_Mesh* aMeshDS = GetMeshDS();
+ if ( !aMeshDS )
+ return false;
+
+ bool res = false;
+ std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+ // duplicate elements and nodes
+ res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
+ // replce nodes by duplications
+ res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
+ return res;
+}
+
+//================================================================================
+/*!
+ \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+ \param theMeshDS - mesh instance
+ \param theElems - the elements replicated or modified (nodes should be changed)
+ \param theNodesNot - nodes to NOT replicate
+ \param theNodeNodeMap - relation of old node to new created node
+ \param theIsDoubleElem - flag os to replicate element or modify
+ \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+//================================================================================
+
+bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
+ const TIDSortedElemSet& theElems,
+ const TIDSortedElemSet& theNodesNot,
+ std::map< const SMDS_MeshNode*,
+ const SMDS_MeshNode* >& theNodeNodeMap,
+ const bool theIsDoubleElem )
+{
+ MESSAGE("doubleNodes");
+ // iterate on through element and duplicate them (by nodes duplication)
+ bool res = false;
+ TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+ for ( ; elemItr != theElems.end(); ++elemItr )
+ {
+ const SMDS_MeshElement* anElem = *elemItr;
+ if (!anElem)
+ continue;
+
+ bool isDuplicate = false;
+ // duplicate nodes to duplicate element
+ std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
+ SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
+ int ind = 0;
+ while ( anIter->more() )
+ {
+
+ SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
+ SMDS_MeshNode* aNewNode = aCurrNode;
+ if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
+ aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
+ else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
+ {
+ // duplicate node
+ aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
+ theNodeNodeMap[ aCurrNode ] = aNewNode;
+ myLastCreatedNodes.Append( aNewNode );
+ }
+ isDuplicate |= (aCurrNode != aNewNode);
+ newNodes[ ind++ ] = aNewNode;
+ }
+ if ( !isDuplicate )
+ continue;
+
+ if ( theIsDoubleElem )
+ AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
+ else
+ {
+ MESSAGE("ChangeElementNodes");
+ theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
+ }
+ res = true;
+ }
+ return res;
+}
+
+//================================================================================
+/*!
+ \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+ \param theNodes - identifiers of nodes to be doubled
+ \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
+ nodes. If list of element identifiers is empty then nodes are doubled but
+ they not assigned to elements
+ \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+//================================================================================
+
+bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
+ const std::list< int >& theListOfModifiedElems )
+{
+ MESSAGE("DoubleNodes");
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ if ( theListOfNodes.size() == 0 )
+ return false;
+
+ SMESHDS_Mesh* aMeshDS = GetMeshDS();
+ if ( !aMeshDS )
+ return false;
+
+ // iterate through nodes and duplicate them
+
+ std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+
+ std::list< int >::const_iterator aNodeIter;
+ for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
+ {
+ int aCurr = *aNodeIter;
+ SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
+ if ( !aNode )
+ continue;
+
+ // duplicate node
+
+ const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
+ if ( aNewNode )
+ {
+ anOldNodeToNewNode[ aNode ] = aNewNode;
+ myLastCreatedNodes.Append( aNewNode );
+ }
+ }
+
+ // Create map of new nodes for modified elements
+
+ std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
+
+ std::list< int >::const_iterator anElemIter;
+ for ( anElemIter = theListOfModifiedElems.begin();
+ anElemIter != theListOfModifiedElems.end(); ++anElemIter )
+ {
+ int aCurr = *anElemIter;
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
+ if ( !anElem )
+ continue;
+
+ vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
+
+ SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
+ int ind = 0;
+ while ( anIter->more() )
+ {
+ SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
+ if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
+ {
+ const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
+ aNodeArr[ ind++ ] = aNewNode;
}
- break; // do not return because it s necessary to remove tmp faces
+ else
+ aNodeArr[ ind++ ] = aCurrNode;
}
+ anElemToNodes[ anElem ] = aNodeArr;
+ }
- // set nodes to merge
- // -------------------
+ // Change nodes of elements
- if ( face[0] && face[1] ) {
- int nbNodes = face[0]->NbNodes();
- if ( nbNodes != face[1]->NbNodes() ) {
- MESSAGE("Diff nb of face nodes");
- aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
- break; // do not return because it s necessary to remove tmp faces
+ std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
+ anElemToNodesIter = anElemToNodes.begin();
+ for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
+ {
+ const SMDS_MeshElement* anElem = anElemToNodesIter->first;
+ vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
+ if ( anElem )
+ {
+ MESSAGE("ChangeElementNodes");
+ aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
}
- bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
- if ( nbNodes == 3 ) {
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
- nReplaceMap.insert( TNodeNodeMap::value_type
- ( notLinkNodes1[0], notLinkNodes2[0] ));
+ }
+
+ return true;
+}
+
+namespace {
+
+ //================================================================================
+ /*!
+ \brief Check if element located inside shape
+ \return TRUE if IN or ON shape, FALSE otherwise
+ */
+ //================================================================================
+
+ template<class Classifier>
+ bool isInside(const SMDS_MeshElement* theElem,
+ Classifier& theClassifier,
+ const double theTol)
+ {
+ gp_XYZ centerXYZ (0, 0, 0);
+ SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
+ while (aNodeItr->more())
+ centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
+
+ gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
+ theClassifier.Perform(aPnt, theTol);
+ TopAbs_State aState = theClassifier.State();
+ return (aState == TopAbs_IN || aState == TopAbs_ON );
+ }
+
+ //================================================================================
+ /*!
+ * \brief Classifier of the 3D point on the TopoDS_Face
+ * with interaface suitable for isInside()
+ */
+ //================================================================================
+
+ struct _FaceClassifier
+ {
+ Extrema_ExtPS _extremum;
+ BRepAdaptor_Surface _surface;
+ TopAbs_State _state;
+
+ _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
+ {
+ _extremum.Initialize( _surface,
+ _surface.FirstUParameter(), _surface.LastUParameter(),
+ _surface.FirstVParameter(), _surface.LastVParameter(),
+ _surface.Tolerance(), _surface.Tolerance() );
+ }
+ void Perform(const gp_Pnt& aPnt, double theTol)
+ {
+ _state = TopAbs_OUT;
+ _extremum.Perform(aPnt);
+ if ( _extremum.IsDone() )
+ for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
+ _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
+ }
+ TopAbs_State State() const
+ {
+ return _state;
+ }
+ };
+}
+
+//================================================================================
+/*!
+ \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+ \param theElems - group of of elements (edges or faces) to be replicated
+ \param theNodesNot - group of nodes not to replicate
+ \param theShape - shape to detect affected elements (element which geometric center
+ located on or inside shape).
+ The replicated nodes should be associated to affected elements.
+ \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+//================================================================================
+
+bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
+ const TIDSortedElemSet& theNodesNot,
+ const TopoDS_Shape& theShape )
+{
+ if ( theShape.IsNull() )
+ return false;
+
+ const double aTol = Precision::Confusion();
+ auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
+ auto_ptr<_FaceClassifier> aFaceClassifier;
+ if ( theShape.ShapeType() == TopAbs_SOLID )
+ {
+ bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
+ bsc3d->PerformInfinitePoint(aTol);
+ }
+ else if (theShape.ShapeType() == TopAbs_FACE )
+ {
+ aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
+ }
+
+ // iterates on indicated elements and get elements by back references from their nodes
+ TIDSortedElemSet anAffected;
+ TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+ for ( ; elemItr != theElems.end(); ++elemItr )
+ {
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+ if (!anElem)
+ continue;
+
+ SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+ while ( nodeItr->more() )
+ {
+ const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+ if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+ continue;
+ SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+ while ( backElemItr->more() )
+ {
+ const SMDS_MeshElement* curElem = backElemItr->next();
+ if ( curElem && theElems.find(curElem) == theElems.end() &&
+ ( bsc3d.get() ?
+ isInside( curElem, *bsc3d, aTol ) :
+ isInside( curElem, *aFaceClassifier, aTol )))
+ anAffected.insert( curElem );
}
- else {
- for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
- // analyse link orientation in faces
- int i1 = iLinkNode[ iSide ][ 0 ];
- int i2 = iLinkNode[ iSide ][ 1 ];
- reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
- // if notLinkNodes are the first and the last ones, then
- // their order does not correspond to the link orientation
- if (( i1 == 1 && i2 == 2 ) ||
- ( i1 == 2 && i2 == 1 ))
- reverse[ iSide ] = !reverse[ iSide ];
- }
- if ( reverse[0] == reverse[1] ) {
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
- for(int nn=0; nn<nbNodes-2; nn++) {
- nReplaceMap.insert( TNodeNodeMap::value_type
- ( notLinkNodes1[nn], notLinkNodes2[nn] ));
- }
+ }
+ }
+ return DoubleNodes( theElems, theNodesNot, anAffected );
+}
+
+/*!
+ * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
+ * The list of groups must describe a partition of the mesh volumes.
+ * The nodes of the internal faces at the boundaries of the groups are doubled.
+ * In option, the internal faces are replaced by flat elements.
+ * Triangles are transformed in prisms, and quadrangles in hexahedrons.
+ * @param theElems - list of groups of volumes, where a group of volume is a set of
+ * SMDS_MeshElements sorted by Id.
+ * @param createJointElems - if TRUE, create the elements
+ * @return TRUE if operation has been completed successfully, FALSE otherwise
+ */
+bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
+ bool createJointElems)
+{
+ MESSAGE("------------------------------------------------------");
+ MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
+ MESSAGE("------------------------------------------------------");
+
+ SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
+ meshDS->BuildDownWardConnectivity(false);
+ CHRONO(50);
+ SMDS_UnstructuredGrid *grid = meshDS->getGrid();
+
+ // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
+ // build the list of nodes shared by 2 or more domains, with their domain indexes
+
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
+ std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
+ faceDomains.clear();
+ nodeDomains.clear();
+ std::map<int,int> emptyMap;
+ emptyMap.clear();
+
+ for (int idom = 0; idom < theElems.size(); idom++)
+ {
+
+ // --- build a map (face to duplicate --> volume to modify)
+ // with all the faces shared by 2 domains (group of elements)
+ // and corresponding volume of this domain, for each shared face.
+ // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
+
+ const TIDSortedElemSet& domain = theElems[idom];
+ TIDSortedElemSet::const_iterator elemItr = domain.begin();
+ for (; elemItr != domain.end(); ++elemItr)
+ {
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
+ if (!anElem)
+ continue;
+ int vtkId = anElem->getVtkId();
+ int neighborsVtkIds[NBMAXNEIGHBORS];
+ int downIds[NBMAXNEIGHBORS];
+ unsigned char downTypes[NBMAXNEIGHBORS];
+ int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+ for (int n = 0; n < nbNeighbors; n++)
+ {
+ int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
+ const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
+ if (! domain.count(elem)) // neighbor is in another domain : face is shared
+ {
+ DownIdType face(downIds[n], downTypes[n]);
+ if (!faceDomains.count(face))
+ faceDomains[face] = emptyMap; // create an empty entry for face
+ if (!faceDomains[face].count(idom))
+ {
+ faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+ }
+ }
+ }
}
- else {
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
- for(int nn=0; nn<nbNodes-2; nn++) {
- nReplaceMap.insert( TNodeNodeMap::value_type
- ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
- }
+ }
+
+ MESSAGE("Number of shared faces " << faceDomains.size());
+
+ // --- for each shared face, get the nodes
+ // for each node, for each domain of the face, create a clone of the node
+
+ std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
+ for( ; itface != faceDomains.end();++itface )
+ {
+ DownIdType face = itface->first;
+ std::map<int,int> domvol = itface->second;
+ std::set<int> oldNodes;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ std::set<int>::iterator itn = oldNodes.begin();
+ for (;itn != oldNodes.end(); ++itn)
+ {
+ int oldId = *itn;
+ if (!nodeDomains.count(oldId))
+ nodeDomains[oldId] = emptyMap; // create an empty entry for node
+ std::map<int,int>::iterator itdom = domvol.begin();
+ for(; itdom != domvol.end(); ++itdom)
+ {
+ int idom = itdom->first;
+ if ( nodeDomains[oldId].empty() )
+ nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
+ else
+ {
+ double *coords = grid->GetPoint(oldId);
+ SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
+ int newId = newNode->getVtkId();
+ nodeDomains[oldId][idom] = newId; // cloned node for other domains
+ }
+ }
}
- }
+ }
- // add other links of the faces to linkList
- // -----------------------------------------
+ // --- iterate on shared faces (volumes to modify, face to extrude)
+ // get node id's of the face (id SMDS = id VTK)
+ // create flat element with old and new nodes if requested
- //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
- for ( iNode = 0; iNode < nbNodes; iNode++ ) {
- //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
- linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
- pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
- if ( !iter_isnew.second ) { // already in a set: no need to process
- linkIdSet.erase( iter_isnew.first );
+ if (createJointElems)
+ {
+ itface = faceDomains.begin();
+ for( ; itface != faceDomains.end();++itface )
+ {
+ DownIdType face = itface->first;
+ std::set<int> oldNodes;
+ std::set<int>::iterator itn;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ std::map<int,int> localClonedNodeIds;
+
+ std::map<int,int> domvol = itface->second;
+ std::map<int,int>::iterator itdom = domvol.begin();
+ int dom1 = itdom->first;
+ int vtkVolId = itdom->second;
+ itdom++;
+ int dom2 = itdom->first;
+
+ localClonedNodeIds.clear();
+ for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
+ {
+ int oldId = *itn;
+ int refid = oldId;
+ if (nodeDomains[oldId].count(dom1))
+ refid = nodeDomains[oldId][dom1];
+ else
+ MESSAGE("--- problem domain node " << dom1 << " " << oldId);
+ int newid = oldId;
+ if (nodeDomains[oldId].count(dom2))
+ newid = nodeDomains[oldId][dom2];
+ else
+ MESSAGE("--- problem domain node " << dom2 << " " << oldId);
+ localClonedNodeIds[oldId] = newid;
+ }
+ meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
}
- else // new in set == encountered for the first time: add
+ }
+
+ // --- iterate on shared faces (volumes to modify, face to extrude)
+ // get node id's of the face
+ // replace old nodes by new nodes in volumes, and update inverse connectivity
+
+ itface = faceDomains.begin();
+ for( ; itface != faceDomains.end();++itface )
+ {
+ DownIdType face = itface->first;
+ std::set<int> oldNodes;
+ std::set<int>::iterator itn;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ std::map<int,int> localClonedNodeIds;
+
+ std::map<int,int> domvol = itface->second;
+ std::map<int,int>::iterator itdom = domvol.begin();
+ for(; itdom != domvol.end(); ++itdom)
{
- //const SMDS_MeshNode* n1 = nodes[ iNode ];
- //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
- const SMDS_MeshNode* n1 = fnodes1[ iNode ];
- const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
- linkList[0].push_back ( TPairOfNodes( n1, n2 ));
- linkList[1].push_back ( TPairOfNodes( nReplaceMap[n1], nReplaceMap[n2] ));
+ int idom = itdom->first;
+ int vtkVolId = itdom->second;
+ localClonedNodeIds.clear();
+ for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
+ {
+ int oldId = *itn;
+ if (nodeDomains[oldId].count(idom))
+ localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
+ }
+ meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
}
- }
- } // 2 faces found
- } // loop on link lists
+ }
+ grid->BuildLinks();
- if ( aResult == SEW_OK &&
- ( linkIt[0] != linkList[0].end() ||
- !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
- MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
- " " << (faceSetPtr[1]->empty()));
- aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+ // TODO replace also old nodes by new nodes in faces and edges
+ CHRONOSTOP(50);
+ counters::stats();
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Generates skin mesh (containing 2D cells) from 3D mesh
+ * The created 2D mesh elements based on nodes of free faces of boundary volumes
+ * \return TRUE if operation has been completed successfully, FALSE otherwise
+ */
+//================================================================================
+
+bool SMESH_MeshEditor::Make2DMeshFrom3D()
+{
+ // iterates on volume elements and detect all free faces on them
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+ if (!aMesh)
+ return false;
+ //bool res = false;
+ int nbFree = 0, nbExisted = 0, nbCreated = 0;
+ SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
+ while(vIt->more())
+ {
+ const SMDS_MeshVolume* volume = vIt->next();
+ SMDS_VolumeTool vTool( volume );
+ vTool.SetExternalNormal();
+ const bool isPoly = volume->IsPoly();
+ const bool isQuad = volume->IsQuadratic();
+ for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
+ {
+ if (!vTool.IsFreeFace(iface))
+ continue;
+ nbFree++;
+ vector<const SMDS_MeshNode *> nodes;
+ int nbFaceNodes = vTool.NbFaceNodes(iface);
+ const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
+ int inode = 0;
+ for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
+ nodes.push_back(faceNodes[inode]);
+ if (isQuad)
+ for ( inode = 1; inode < nbFaceNodes; inode += 2)
+ nodes.push_back(faceNodes[inode]);
+
+ // add new face based on volume nodes
+ if (aMesh->FindFace( nodes ) ) {
+ nbExisted++;
+ continue; // face already exsist
+ }
+ AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
+ nbCreated++;
+ }
}
+ return ( nbFree==(nbExisted+nbCreated) );
+}
- // ====================================================================
- // 3. Replace nodes in elements of the side 1 and remove replaced nodes
- // ====================================================================
+namespace
+{
+ inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
+ {
+ if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
+ return n;
+ return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
+ }
+}
+//================================================================================
+/*!
+ * \brief Creates missing boundary elements
+ * \param elements - elements whose boundary is to be checked
+ * \param dimension - defines type of boundary elements to create
+ * \param group - a group to store created boundary elements in
+ * \param targetMesh - a mesh to store created boundary elements in
+ * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
+ * \param toCopyExistingBondary - if true, not only new but also pre-existing
+ * boundary elements will be copied into the targetMesh
+ */
+//================================================================================
+
+void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
+ Bnd_Dimension dimension,
+ SMESH_Group* group/*=0*/,
+ SMESH_Mesh* targetMesh/*=0*/,
+ bool toCopyElements/*=false*/,
+ bool toCopyExistingBondary/*=false*/)
+{
+ SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
+ SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
+ // hope that all elements are of the same type, do not check them all
+ if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
+ throw SALOME_Exception(LOCALIZED("wrong element type"));
- // delete temporary faces: they are in reverseElements of actual nodes
- SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
- while ( tmpFaceIt->more() )
- aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+ if ( !targetMesh )
+ toCopyElements = toCopyExistingBondary = false;
- if ( aResult != SEW_OK)
- return aResult;
+ SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
+ SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
- list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
- // loop on nodes replacement map
- TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
- for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
- if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
- const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
- nodeIDsToRemove.push_back( nToRemove->GetID() );
- // loop on elements sharing nToRemove
- SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
- while ( invElemIt->more() ) {
- const SMDS_MeshElement* e = invElemIt->next();
- // get a new suite of nodes: make replacement
- int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
- vector< const SMDS_MeshNode*> nodes( nbNodes );
- SMDS_ElemIteratorPtr nIt = e->nodesIterator();
- while ( nIt->more() ) {
- const SMDS_MeshNode* n =
- static_cast<const SMDS_MeshNode*>( nIt->next() );
- nnIt = nReplaceMap.find( n );
- if ( nnIt != nReplaceMap.end() ) {
- nbReplaced++;
- n = (*nnIt).second;
+ SMDS_VolumeTool vTool;
+ TIDSortedElemSet emptySet, avoidSet;
+ int inode;
+
+ typedef vector<const SMDS_MeshNode*> TConnectivity;
+
+ SMDS_ElemIteratorPtr eIt;
+ if (elements.empty())
+ eIt = aMesh->elementsIterator(elemType);
+ else
+ eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+
+ while (eIt->more())
+ {
+ const SMDS_MeshElement* elem = eIt->next();
+ const int iQuad = elem->IsQuadratic();
+
+ // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
+ vector<const SMDS_MeshElement*> presentBndElems;
+ vector<TConnectivity> missingBndElems;
+ TConnectivity nodes;
+ if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
+ {
+ vTool.SetExternalNormal();
+ for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
+ {
+ if (!vTool.IsFreeFace(iface))
+ continue;
+ int nbFaceNodes = vTool.NbFaceNodes(iface);
+ const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
+ if ( missType == SMDSAbs_Edge ) // boundary edges
+ {
+ nodes.resize( 2+iQuad );
+ for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
+ {
+ for ( int j = 0; j < nodes.size(); ++j )
+ nodes[j] =nn[i+j];
+ if ( const SMDS_MeshElement* edge =
+ aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
+ presentBndElems.push_back( edge );
+ else
+ missingBndElems.push_back( nodes );
}
- nodes[ i++ ] = n;
}
- // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
- // elemIDsToRemove.push_back( e->GetID() );
- // else
- if ( nbReplaced )
- aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
+ else // boundary face
+ {
+ nodes.clear();
+ for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
+ nodes.push_back( nn[inode] );
+ if (iQuad)
+ for ( inode = 1; inode < nbFaceNodes; inode += 2)
+ nodes.push_back( nn[inode] );
+
+ if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
+ presentBndElems.push_back( f );
+ else
+ missingBndElems.push_back( nodes );
+ }
+ }
+ }
+ else // elem is a face ------------------------------------------
+ {
+ avoidSet.clear(), avoidSet.insert( elem );
+ int nbNodes = elem->NbCornerNodes();
+ nodes.resize( 2 /*+ iQuad*/);
+ for ( int i = 0; i < nbNodes; i++ )
+ {
+ nodes[0] = elem->GetNode(i);
+ nodes[1] = elem->GetNode((i+1)%nbNodes);
+ if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
+ continue; // not free link
+
+ //if ( iQuad )
+ //nodes[2] = elem->GetNode( i + nbNodes );
+ if ( const SMDS_MeshElement* edge =
+ aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
+ presentBndElems.push_back( edge );
+ else
+ missingBndElems.push_back( nodes );
}
}
- Remove( nodeIDsToRemove, true );
+ // 2. Add missing boundary elements
+ if ( targetMesh != myMesh )
+ // instead of making a map of nodes in this mesh and targetMesh,
+ // we create nodes with same IDs. We can renumber them later, if needed
+ for ( int i = 0; i < missingBndElems.size(); ++i )
+ {
+ TConnectivity& srcNodes = missingBndElems[i];
+ TConnectivity nodes( srcNodes.size() );
+ for ( inode = 0; inode < nodes.size(); ++inode )
+ nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
+ tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+ }
+ else
+ for ( int i = 0; i < missingBndElems.size(); ++i )
+ {
+ TConnectivity& nodes = missingBndElems[i];
+ tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+ }
- return aResult;
+ // 3. Copy present boundary elements
+ if ( toCopyExistingBondary )
+ for ( int i = 0 ; i < presentBndElems.size(); ++i )
+ {
+ const SMDS_MeshElement* e = presentBndElems[i];
+ TConnectivity nodes( e->NbNodes() );
+ for ( inode = 0; inode < nodes.size(); ++inode )
+ nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
+ tgtEditor.AddElement(nodes, missType, e->IsPoly());
+ // leave only missing elements in tgtEditor.myLastCreatedElems
+ tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
+ }
+ } // loop on given elements
+
+ // 4. Fill group with missing boundary elements
+ if ( group )
+ {
+ if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
+ for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
+ g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
+ }
+ tgtEditor.myLastCreatedElems.Clear();
+
+ // 5. Copy given elements
+ if ( toCopyElements )
+ {
+ if (elements.empty())
+ eIt = aMesh->elementsIterator(elemType);
+ else
+ eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+ while (eIt->more())
+ {
+ const SMDS_MeshElement* elem = eIt->next();
+ TConnectivity nodes( elem->NbNodes() );
+ for ( inode = 0; inode < nodes.size(); ++inode )
+ nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
+ tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
+
+ tgtEditor.myLastCreatedElems.Clear();
+ }
+ }
+ return;
}