-// Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
//
// 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
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "SMESH_MeshEditor.hxx"
-#include "SMDS_FaceOfNodes.hxx"
-#include "SMDS_VolumeTool.hxx"
+#include "SMDS_Downward.hxx"
#include "SMDS_EdgePosition.hxx"
+#include "SMDS_FaceOfNodes.hxx"
#include "SMDS_FacePosition.hxx"
-#include "SMDS_SpacePosition.hxx"
-#include "SMDS_MeshGroup.hxx"
#include "SMDS_LinearEdge.hxx"
-#include "SMDS_Downward.hxx"
+#include "SMDS_MeshGroup.hxx"
#include "SMDS_SetIterator.hxx"
-
+#include "SMDS_SpacePosition.hxx"
+#include "SMDS_VolumeTool.hxx"
#include "SMESHDS_Group.hxx"
#include "SMESHDS_Mesh.hxx"
-
#include "SMESH_Algo.hxx"
#include "SMESH_ControlsDef.hxx"
#include "SMESH_Group.hxx"
+#include "SMESH_Mesh.hxx"
+#include "SMESH_MeshAlgos.hxx"
#include "SMESH_MesherHelper.hxx"
#include "SMESH_OctreeNode.hxx"
#include "SMESH_subMesh.hxx"
-#include <Basics_OCCTVersion.hxx>
-
#include "utilities.h"
+#include "chrono.hxx"
#include <BRepAdaptor_Surface.hxx>
#include <BRepBuilderAPI_MakeEdge.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 <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 <TopTools_ListOfShape.hxx>
#include <TopTools_SequenceOfShape.hxx>
#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Solid.hxx>
#include <gp.hxx>
#include <sstream>
#include <boost/tuple/tuple.hpp>
+#include <boost/container/flat_set.hpp>
#include <Standard_Failure.hxx>
#include <Standard_ErrorHandler.hxx>
+#include "SMESH_TryCatch.hxx" // include after OCCT headers!
+
+#include <smIdType.hxx>
+
#define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
using namespace std;
using namespace SMESH::Controls;
-typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
-
//=======================================================================
//function : SMESH_MeshEditor
//purpose :
{
}
+//================================================================================
+/*!
+ * \brief Return mesh DS
+ */
+//================================================================================
+
+SMESHDS_Mesh * SMESH_MeshEditor::GetMeshDS()
+{
+ return myMesh->GetMeshDS();
+}
+
+
//================================================================================
/*!
* \brief Clears myLastCreatedNodes and myLastCreatedElems
*/
//================================================================================
-void SMESH_MeshEditor::CrearLastCreated()
+void SMESH_MeshEditor::ClearLastCreated()
{
- myLastCreatedNodes.Clear();
- myLastCreatedElems.Clear();
+ SMESHUtils::FreeVector( myLastCreatedElems );
+ SMESHUtils::FreeVector( myLastCreatedNodes );
}
+//================================================================================
+/*!
+ * \brief Initializes members by an existing element
+ * \param [in] elem - the source element
+ * \param [in] basicOnly - if true, does not set additional data of Ball and Polyhedron
+ */
+//================================================================================
+
+SMESH_MeshEditor::ElemFeatures&
+SMESH_MeshEditor::ElemFeatures::Init( const SMDS_MeshElement* elem, bool basicOnly )
+{
+ if ( elem )
+ {
+ myType = elem->GetType();
+ if ( myType == SMDSAbs_Face || myType == SMDSAbs_Volume )
+ {
+ myIsPoly = elem->IsPoly();
+ if ( myIsPoly )
+ {
+ myIsQuad = elem->IsQuadratic();
+ if ( myType == SMDSAbs_Volume && !basicOnly )
+ {
+ myPolyhedQuantities = static_cast<const SMDS_MeshVolume* >( elem )->GetQuantities();
+ }
+ }
+ }
+ else if ( myType == SMDSAbs_Ball && !basicOnly )
+ {
+ myBallDiameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
+ }
+ }
+ return *this;
+}
//=======================================================================
/*!
SMDS_MeshElement*
SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
- const SMDSAbs_ElementType type,
- const bool isPoly,
- const int ID,
- const double ballDiameter)
+ const ElemFeatures& features)
{
- //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
SMDS_MeshElement* e = 0;
int nbnode = node.size();
SMESHDS_Mesh* mesh = GetMeshDS();
- switch ( type ) {
+ const smIdType ID = features.myID;
+
+ switch ( features.myType ) {
case SMDSAbs_Face:
- if ( !isPoly ) {
+ if ( !features.myIsPoly ) {
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 e = mesh->AddFace (node[0], node[1], node[2], node[3],
node[4], node[5] );
}
+ else if (nbnode == 7) {
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6] );
+ }
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], node[8] );
}
- } else {
+ }
+ else if ( !features.myIsQuad )
+ {
if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
else e = mesh->AddPolygonalFace (node );
}
+ else if ( nbnode % 2 == 0 ) // just a protection
+ {
+ if ( ID >= 1 ) e = mesh->AddQuadPolygonalFaceWithID(node, ID);
+ else e = mesh->AddQuadPolygonalFace (node );
+ }
break;
case SMDSAbs_Volume:
- if ( !isPoly ) {
+ if ( !features.myIsPoly ) {
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] );
node[8], node[9], node[10],node[11],
node[12],node[13],node[14] );
}
+ else if (nbnode == 18) {
+ 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],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] );
+ }
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[24],node[25],node[26] );
}
}
+ else if ( !features.myIsQuad )
+ {
+ if ( ID >= 1 ) e = mesh->AddPolyhedralVolumeWithID(node, features.myPolyhedQuantities, ID);
+ else e = mesh->AddPolyhedralVolume (node, features.myPolyhedQuantities );
+ }
+ else
+ {
+ // if ( ID >= 1 ) e = mesh->AddQuadPolyhedralVolumeWithID(node, features.myPolyhedQuantities,ID);
+ // else e = mesh->AddQuadPolyhedralVolume (node, features.myPolyhedQuantities );
+ }
break;
case SMDSAbs_Edge:
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());
+ else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z() );
break;
case SMDSAbs_Ball:
- if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
- else e = mesh->AddBall (node[0], ballDiameter);
+ if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], features.myBallDiameter, ID);
+ else e = mesh->AddBall (node[0], features.myBallDiameter );
break;
default:;
}
- if ( e ) myLastCreatedElems.Append( e );
+ if ( e ) myLastCreatedElems.push_back( e );
return e;
}
*/
//=======================================================================
-SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
- const SMDSAbs_ElementType type,
- const bool isPoly,
- const int ID)
+SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<smIdType> & nodeIDs,
+ const ElemFeatures& features)
{
vector<const SMDS_MeshNode*> nodes;
nodes.reserve( nodeIDs.size() );
- vector<int>::const_iterator id = nodeIDs.begin();
+ vector<smIdType>::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 );
+ return AddElement( nodes, features );
}
//=======================================================================
// Modify a compute state of sub-meshes which become empty
//=======================================================================
-int SMESH_MeshEditor::Remove (const list< int >& theIDs,
+smIdType SMESH_MeshEditor::Remove (const list< smIdType >& theIDs,
const bool isNodes )
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
SMESHDS_Mesh* aMesh = GetMeshDS();
set< SMESH_subMesh *> smmap;
- int removed = 0;
- list<int>::const_iterator it = theIDs.begin();
+ smIdType removed = 0;
+ list<smIdType>::const_iterator it = theIDs.begin();
for ( ; it != theIDs.end(); it++ ) {
const SMDS_MeshElement * elem;
if ( isNodes )
//================================================================================
/*!
- * \brief Create 0D elements on all nodes of the given object except those
- * nodes on which a 0D element already exists.
+ * \brief Create 0D elements on all nodes of the given object.
* \param elements - Elements on whose nodes to create 0D elements; if empty,
* the all mesh is treated
* \param all0DElems - returns all 0D elements found or created on nodes of \a elements
+ * \param duplicateElements - to add one more 0D element to a node or not
*/
//================================================================================
void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
- TIDSortedElemSet& all0DElems )
+ TIDSortedElemSet& all0DElems,
+ const bool duplicateElements )
{
- typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator> TSetIterator;
SMDS_ElemIteratorPtr elemIt;
if ( elements.empty() )
+ {
elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
+ }
else
- elemIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+ {
+ elemIt = SMESHUtils::elemSetIterator( elements );
+ }
while ( elemIt->more() )
{
{
const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
- if ( it0D->more() )
- all0DElems.insert( it0D->next() );
- else {
- myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
- all0DElems.insert( myLastCreatedElems.Last() );
+ if ( duplicateElements || !it0D->more() )
+ {
+ myLastCreatedElems.push_back( GetMeshDS()->Add0DElement( n ));
+ all0DElems.insert( myLastCreatedElems.back() );
}
+ while ( it0D->more() )
+ all0DElems.insert( it0D->next() );
}
}
}
int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
SMESHDS_Mesh * aMesh = GetMeshDS();
if ( aMesh->ShapeToMesh().IsNull() )
}
else
{
- const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
- map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
- for ( ; id_sm != id2sm.end(); ++id_sm )
- if ( id_sm->second->Contains( theElem ))
- return id_sm->first;
+ SMESHDS_SubMeshIteratorPtr smIt = GetMeshDS()->SubMeshes();
+ while ( const SMESHDS_SubMesh* sm = smIt->next() )
+ if ( sm->Contains( theElem ))
+ return sm->GetID();
}
- //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
return 0;
}
}
//=======================================================================
-//function : ShiftNodesQuadTria
-//purpose : auxilary
-// Shift nodes in the array corresponded to quadratic triangle
+//function : shiftNodesQuadTria
+//purpose : Shift nodes in the array corresponded to quadratic triangle
// example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
//=======================================================================
-static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
+
+static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
{
const SMDS_MeshNode* nd1 = aNodes[0];
aNodes[0] = aNodes[1];
}
//=======================================================================
-//function : edgeConnectivity
-//purpose : auxilary
-// return number of the edges connected with the theNode.
-// if theEdges has connections with the other type of the
-// elements, return -1
+//function : getNodesFromTwoTria
+//purpose :
//=======================================================================
-static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
-{
- SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
- int nb=0;
- while(elemIt->more()) {
- elemIt->next();
- nb++;
- }
- return nb;
-}
-
-//=======================================================================
-//function : GetNodesFromTwoTria
-//purpose : auxilary
-// Shift nodes in the array corresponded to quadratic triangle
-// example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
-//=======================================================================
-static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
+static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
const SMDS_MeshElement * theTria2,
- const SMDS_MeshNode* N1[],
- const SMDS_MeshNode* N2[])
+ vector< const SMDS_MeshNode*>& N1,
+ vector< const SMDS_MeshNode*>& N2)
{
- SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
- int i=0;
- while(i<6) {
- N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
- i++;
- }
- if(it->more()) return false;
- it = theTria2->nodesIterator();
- i=0;
- while(i<6) {
- N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
- i++;
- }
- if(it->more()) return false;
+ N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
+ if ( N1.size() < 6 ) return false;
+ N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
+ if ( N2.size() < 6 ) return false;
int sames[3] = {-1,-1,-1};
int nbsames = 0;
- int j;
+ int i, j;
for(i=0; i<3; i++) {
for(j=0; j<3; j++) {
if(N1[i]==N2[j]) {
}
if(nbsames!=2) return false;
if(sames[0]>-1) {
- ShiftNodesQuadTria(N1);
+ shiftNodesQuadTria(N1);
if(sames[1]>-1) {
- ShiftNodesQuadTria(N1);
+ shiftNodesQuadTria(N1);
}
}
i = sames[0] + sames[1] + sames[2];
for(; i<2; i++) {
- ShiftNodesQuadTria(N2);
+ shiftNodesQuadTria(N2);
}
- // now we receive following N1 and N2 (using numeration as above image)
+ // now we receive following N1 and N2 (using numeration as in the image below)
// 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
+ // i.e. first nodes from both arrays form a new diagonal
return true;
}
bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
const SMDS_MeshElement * theTria2 )
{
- MESSAGE("InverseDiag");
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
- if (!theTria1 || !theTria2)
+ if ( !theTria1 || !theTria2 ||
+ !dynamic_cast<const SMDS_MeshCell*>( theTria1 ) ||
+ !dynamic_cast<const SMDS_MeshCell*>( theTria2 ) ||
+ theTria1->GetType() != SMDSAbs_Face ||
+ theTria2->GetType() != SMDSAbs_Face )
return false;
- 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)) {
-
+ (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 ) |\ |
// |/ | | \|
// put nodes in array and find out indices of the same ones
const SMDS_MeshNode* aNodes [6];
- int sameInd [] = { 0, 0, 0, 0, 0, 0 };
+ int sameInd [] = { -1, -1, -1, -1, -1, -1 };
int i = 0;
SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
while ( it->more() ) {
}
// find indices of 1,2 and of A,B in theTria1
- int iA = 0, iB = 0, i1 = 0, i2 = 0;
+ int iA = -1, iB = 0, i1 = 0, i2 = 0;
for ( i = 0; i < 6; i++ ) {
- if ( sameInd [ i ] == 0 ) {
+ if ( sameInd [ i ] == -1 ) {
if ( i < 3 ) i1 = i;
else i2 = i;
}
else if (i < 3) {
- if ( iA ) iB = i;
- else iA = i;
+ if ( iA >= 0) iB = i;
+ else iA = i;
}
}
// nodes 1 and 2 should not be the same
} // end if(F1 && F2)
// check case of quadratic faces
- if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
+ if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
+ theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
return false;
- if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
+ if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
+ theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
return false;
// 5
// 4 +--+--+ 3
// 8
- const SMDS_MeshNode* N1 [6];
- const SMDS_MeshNode* N2 [6];
- if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
+ vector< const SMDS_MeshNode* > N1;
+ vector< const SMDS_MeshNode* > N2;
+ 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)
// i.e. first nodes from both arrays determ new diagonal
- const SMDS_MeshNode* N1new [6];
- const SMDS_MeshNode* N2new [6];
- N1new[0] = N1[0];
- N1new[1] = N2[0];
- N1new[2] = N2[1];
- N1new[3] = N1[4];
- N1new[4] = N2[3];
- N1new[5] = N1[5];
- N2new[0] = N1[0];
- N2new[1] = N1[1];
- N2new[2] = N2[0];
- N2new[3] = N1[3];
- N2new[4] = N2[5];
- N2new[5] = N1[4];
- // replaces nodes in faces
- GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
- GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
-
+ vector< const SMDS_MeshNode*> N1new( N1.size() );
+ vector< const SMDS_MeshNode*> N2new( N2.size() );
+ N1new.back() = N1.back(); // central node of biquadratic
+ N2new.back() = N2.back();
+ N1new[0] = N1[0]; N2new[0] = N1[0];
+ N1new[1] = N2[0]; N2new[1] = N1[1];
+ N1new[2] = N2[1]; N2new[2] = N2[0];
+ N1new[3] = N1[4]; N2new[3] = N1[3];
+ N1new[4] = N2[3]; N2new[4] = N2[5];
+ N1new[5] = N1[5]; N2new[5] = N1[4];
+ // change nodes in faces
+ GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
+ GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
+
+ // move the central node of biquadratic triangle
+ SMESH_MesherHelper helper( *GetMesh() );
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ const SMDS_MeshElement* tria = is2nd ? theTria2 : theTria1;
+ vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
+ if ( nodes.size() < 7 )
+ continue;
+ helper.SetSubShape( tria->getshapeId() );
+ const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
+ gp_Pnt xyz;
+ if ( F.IsNull() )
+ {
+ xyz = ( SMESH_NodeXYZ( nodes[3] ) +
+ SMESH_NodeXYZ( nodes[4] ) +
+ SMESH_NodeXYZ( nodes[5] )) / 3.;
+ }
+ else
+ {
+ bool checkUV;
+ gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
+ helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
+ helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
+ TopLoc_Location loc;
+ Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
+ xyz = S->Value( uv.X(), uv.Y() );
+ xyz.Transform( loc );
+ if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE && // set UV
+ nodes[6]->getshapeId() > 0 )
+ GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
+ }
+ GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
+ }
return true;
}
SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
while (it->more()) {
const SMDS_MeshElement* elem = it->next();
- if ( elem->NbNodes() == 3 )
+ if ( elem->NbCornerNodes() == 3 )
emap.insert( elem );
}
it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
while (it->more()) {
const SMDS_MeshElement* elem = it->next();
- if ( emap.find( elem ) != emap.end() ) {
- if ( theTria1 ) {
- // theTria1 must be element with minimum ID
- if( theTria1->GetID() < elem->GetID() ) {
- theTria2 = elem;
- }
- else {
- theTria2 = theTria1;
- theTria1 = elem;
- }
- break;
- }
- else {
+ if ( emap.count( elem )) {
+ if ( !theTria1 )
+ {
theTria1 = elem;
}
+ else
+ {
+ theTria2 = elem;
+ // theTria1 must be element with minimum ID
+ if ( theTria2->GetID() < theTria1->GetID() )
+ std::swap( theTria2, theTria1 );
+ return true;
+ }
}
}
- return ( theTria1 && theTria2 );
+ return false;
}
//=======================================================================
bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
const SMDS_MeshNode * theNode2)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- MESSAGE( "::InverseDiag()" );
+ ClearLastCreated();
const SMDS_MeshElement *tr1, *tr2;
if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
return false;
- 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 ( !dynamic_cast<const SMDS_MeshCell*>( tr1 ) ||
+ !dynamic_cast<const SMDS_MeshCell*>( tr2 ))
+ return false;
+
if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
(tr2->GetEntityType() == SMDSEntity_Triangle)) {
bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
const SMDS_MeshNode * theNode2)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- MESSAGE( "::DeleteDiag()" );
+ ClearLastCreated();
const SMDS_MeshElement *tr1, *tr2;
if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
return false;
- 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 ( !dynamic_cast<const SMDS_MeshCell*>( tr1 ) ||
+ !dynamic_cast<const SMDS_MeshCell*>( tr2 ))
+ return false;
+
SMESHDS_Mesh * aMesh = GetMeshDS();
if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
- (tr2->GetEntityType() == SMDSEntity_Triangle)) {
-
+ (tr2->GetEntityType() == SMDSEntity_Triangle))
+ {
const SMDS_MeshNode* aNodes [ 4 ];
if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
return false;
const SMDS_MeshElement* newElem = 0;
newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
- myLastCreatedElems.Append(newElem);
+ myLastCreatedElems.push_back(newElem);
AddToSameGroups( newElem, tr1, aMesh );
int aShapeId = tr1->getshapeId();
if ( aShapeId )
- {
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- }
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+
aMesh->RemoveElement( tr1 );
aMesh->RemoveElement( tr2 );
// 4 +--+--+ 3
// 8
- const SMDS_MeshNode* N1 [6];
- const SMDS_MeshNode* N2 [6];
- if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
+ vector< const SMDS_MeshNode* > N1;
+ vector< const SMDS_MeshNode* > N2;
+ 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)
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);
+ myLastCreatedElems.push_back(newElem);
AddToSameGroups( newElem, tr1, aMesh );
int aShapeId = tr1->getshapeId();
if ( aShapeId )
- {
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- }
+ {
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
aMesh->RemoveElement( tr1 );
aMesh->RemoveElement( tr2 );
bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
{
- MESSAGE("Reorient");
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
if (!theElem)
return false;
if ( !it || !it->more() )
return false;
- switch ( theElem->GetType() ) {
+ const SMDSAbs_ElementType type = theElem->GetType();
+ if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
+ return false;
- case SMDSAbs_Edge:
- case SMDSAbs_Face: {
- if(!theElem->IsQuadratic()) {
- int i = theElem->NbNodes();
- vector<const SMDS_MeshNode*> aNodes( i );
- while ( it->more() )
- aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
- return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
- }
- else {
- // quadratic elements
- if(theElem->GetType()==SMDSAbs_Edge) {
- vector<const SMDS_MeshNode*> aNodes(3);
- aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
- aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
- aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
- return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
- }
- else {
- int nbn = theElem->NbNodes();
- vector<const SMDS_MeshNode*> aNodes(nbn);
- aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
- int i=1;
- for(; i<nbn/2; i++) {
- aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
- }
- for(i=0; i<nbn/2; i++) {
- aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
- }
- return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
- }
+ const SMDSAbs_EntityType geomType = theElem->GetEntityType();
+ if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
+ {
+ const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( theElem );
+ if (!aPolyedre) {
+ MESSAGE("Warning: bad volumic element");
+ return false;
}
- }
- case SMDSAbs_Volume: {
- if (theElem->IsPoly()) {
- // 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;
- }
-
- int nbFaces = aPolyedre->NbFaces();
- vector<const SMDS_MeshNode *> poly_nodes;
- vector<int> quantities (nbFaces);
+ SMDS_VolumeTool vTool( aPolyedre );
+ const int nbFaces = vTool.NbFaces();
+ vector<int> quantities( nbFaces );
+ vector<const SMDS_MeshNode *> poly_nodes;
- // reverse each face of the polyedre
- for (int iface = 1; iface <= nbFaces; iface++) {
- int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
- quantities[iface - 1] = nbFaceNodes;
+ // check if all facets are oriented equally
+ bool sameOri = true;
+ vector<int>& facetOri = quantities; // keep orientation in quantities so far
+ for (int iface = 0; iface < nbFaces; iface++)
+ {
+ facetOri[ iface ] = vTool.IsFaceExternal( iface );
+ if ( facetOri[ iface ] != facetOri[ 0 ])
+ sameOri = false;
+ }
- for (inode = nbFaceNodes; inode >= 1; inode--) {
- const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
- poly_nodes.push_back(curNode);
- }
- }
+ // reverse faces of the polyhedron
+ int neededOri = sameOri ? 1 - facetOri[0] : 1;
+ poly_nodes.reserve( vTool.NbNodes() );
+ for ( int iface = 0; iface < nbFaces; iface++ )
+ {
+ int nbFaceNodes = vTool.NbFaceNodes( iface );
+ const SMDS_MeshNode** nodes = vTool.GetFaceNodes( iface );
+ bool toReverse = ( facetOri[ iface ] != neededOri );
- return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
+ quantities[ iface ] = nbFaceNodes;
+ if ( toReverse )
+ for ( int inode = nbFaceNodes - 1; inode >= 0; inode-- )
+ poly_nodes.push_back( nodes[ inode ]);
+ else
+ poly_nodes.insert( poly_nodes.end(), nodes, nodes + nbFaceNodes );
}
- else {
- SMDS_VolumeTool vTool;
- if ( !vTool.Set( theElem ))
- return false;
- vTool.Inverse();
- MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
- return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
- }
+ return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
}
- default:;
+ else // other elements
+ {
+ vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
+ const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() );
+ if ( interlace.empty() )
+ {
+ std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case
+ }
+ else
+ {
+ SMDS_MeshCell::applyInterlace( interlace, nodes );
+ }
+ return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
}
-
return false;
}
* \brief Reorient faces.
* \param theFaces - the faces to reorient. If empty the whole mesh is meant
* \param theDirection - desired direction of normal of \a theFace
- * \param theFace - one of \a theFaces that sould be oriented according to
+ * \param theFace - one of \a theFaces that should be oriented according to
* \a theDirection and whose orientation defines orientation of other faces
* \return number of reoriented faces.
*/
if ( theFaces.empty() )
{
- SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
+ SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=true*/);
while ( fIt->more() )
theFaces.insert( theFaces.end(), fIt->next() );
}
// orient theFace according to theDirection
gp_XYZ normal;
- SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false );
+ SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
if ( normal * theDirection.XYZ() < 0 )
nbReori += Reorient( theFace );
avoidSet.clear();
avoidSet.insert(theFace);
- NLink link( theFace->GetNode( 0 ), 0 );
+ NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 );
const int nbNodes = theFace->NbCornerNodes();
for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
{
facesNearLink.clear();
nodeIndsOfFace.clear();
- while (( otherFace = FindFaceInSet( link.first, link.second,
- theFaces, avoidSet, &nodeInd1, &nodeInd2 )))
+ while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
+ theFaces, avoidSet,
+ &nodeInd1, &nodeInd2 )))
if ( otherFace != theFace)
{
facesNearLink.push_back( otherFace );
// select a face most co-directed with theFace,
// other faces won't be visited this time
gp_XYZ NF, NOF;
- SMESH_Algo::FaceNormal( theFace, NF, /*normalized=*/false );
+ SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
double proj, maxProj = -1;
for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
- SMESH_Algo::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
+ SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
if (( proj = Abs( NF * NOF )) > maxProj ) {
maxProj = proj;
otherFace = facesNearLink[i];
}
if ( otherFace && otherFace != theFace)
{
- // link must be reverse in otherFace if orientation ot otherFace
+ // link must be reverse in otherFace if orientation to otherFace
// is same as that of theFace
if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
{
return nbReori;
}
+//================================================================================
+/*!
+ * \brief Reorient faces basing on orientation of adjacent volumes.
+ * \param theFaces - faces to reorient. If empty, all mesh faces are treated.
+ * \param theVolumes - reference volumes.
+ * \param theOutsideNormal - to orient faces to have their normal
+ * pointing either \a outside or \a inside the adjacent volumes.
+ * \return number of reoriented faces.
+ */
+//================================================================================
+
+int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces,
+ TIDSortedElemSet & theVolumes,
+ const bool theOutsideNormal)
+{
+ int nbReori = 0;
+
+ SMDS_ElemIteratorPtr faceIt;
+ if ( theFaces.empty() )
+ faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face );
+ else
+ faceIt = SMESHUtils::elemSetIterator( theFaces );
+
+ vector< const SMDS_MeshNode* > faceNodes;
+ TIDSortedElemSet checkedVolumes;
+ set< const SMDS_MeshNode* > faceNodesSet;
+ SMDS_VolumeTool volumeTool;
+
+ while ( faceIt->more() ) // loop on given faces
+ {
+ const SMDS_MeshElement* face = faceIt->next();
+ if ( face->GetType() != SMDSAbs_Face )
+ continue;
+
+ const size_t nbCornersNodes = face->NbCornerNodes();
+ faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+
+ checkedVolumes.clear();
+ SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume );
+ while ( vIt->more() )
+ {
+ const SMDS_MeshElement* volume = vIt->next();
+
+ if ( !checkedVolumes.insert( volume ).second )
+ continue;
+ if ( !theVolumes.empty() && !theVolumes.count( volume ))
+ continue;
+
+ // is volume adjacent?
+ bool allNodesCommon = true;
+ for ( size_t iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN )
+ allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 );
+ if ( !allNodesCommon )
+ continue;
+
+ // get nodes of a corresponding volume facet
+ faceNodesSet.clear();
+ faceNodesSet.insert( faceNodes.begin(), faceNodes.end() );
+ volumeTool.Set( volume );
+ int facetID = volumeTool.GetFaceIndex( faceNodesSet );
+ if ( facetID < 0 ) continue;
+ volumeTool.SetExternalNormal();
+ const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID );
+
+ // compare order of faceNodes and facetNodes
+ const int iQ = 1 + ( nbCornersNodes < faceNodes.size() );
+ int iNN[2];
+ for ( int i = 0; i < 2; ++i )
+ {
+ const SMDS_MeshNode* n = facetNodes[ i*iQ ];
+ for ( size_t iN = 0; iN < nbCornersNodes; ++iN )
+ if ( faceNodes[ iN ] == n )
+ {
+ iNN[ i ] = iN;
+ break;
+ }
+ }
+ bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1];
+ if ( isOutside != theOutsideNormal )
+ nbReori += Reorient( face );
+ }
+ } // loop on given faces
+
+ return nbReori;
+}
+
//=======================================================================
//function : getBadRate
//purpose :
bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
SMESH::Controls::NumericalFunctorPtr theCrit)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- MESSAGE( "::QuadToTri()" );
+ ClearLastCreated();
if ( !theCrit.get() )
return false;
- SMESHDS_Mesh * aMesh = GetMeshDS();
-
+ SMESHDS_Mesh * aMesh = GetMeshDS();
Handle(Geom_Surface) surface;
SMESH_MesherHelper helper( *GetMesh() );
+ myLastCreatedElems.reserve( theElems.size() * 2 );
+
TIDSortedElemSet::iterator itElem;
- for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+ {
const SMDS_MeshElement* elem = *itElem;
if ( !elem || elem->GetType() != SMDSAbs_Face )
continue;
SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
- int aShapeId = FindShape( elem );
+ const int aShapeId = FindShape( elem );
const SMDS_MeshElement* newElem1 = 0;
const SMDS_MeshElement* newElem2 = 0;
- if( !elem->IsQuadratic() ) {
-
- // split liner quadrangle
+ if ( !elem->IsQuadratic() ) // split linear quadrangle
+ {
// for MaxElementLength2D functor we return minimum diagonal for splitting,
// because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
if ( aBadRate1 <= aBadRate2 ) {
newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
}
}
- else {
-
- // split quadratic quadrangle
+ else // split quadratic quadrangle
+ {
+ helper.SetIsQuadratic( true );
+ helper.SetIsBiQuadratic( aNodes.size() == 9 );
- // get surface elem is on
- 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 );
- }
- }
- // find middle point for (0,1,2,3)
- // and create a node in this point;
- const SMDS_MeshNode* newN = 0;
+ helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
if ( aNodes.size() == 9 )
{
- // SMDSEntity_BiQuad_Quadrangle
- newN = aNodes.back();
- }
- else
- {
- gp_XYZ p( 0,0,0 );
- if ( surface.IsNull() )
- {
- for ( int i = 0; i < 4; i++ )
- p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
- p /= 4;
- }
+ helper.SetIsBiQuadratic( true );
+ if ( aBadRate1 <= aBadRate2 )
+ helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
else
- {
- const SMDS_MeshNode* inFaceNode = 0;
- if ( helper.GetNodeUVneedInFaceNode() )
- for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
- if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
- inFaceNode = aNodes[ i ];
-
- TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
- gp_XY uv( 0,0 );
- for ( int i = 0; i < 4; i++ )
- uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
- uv /= 4.;
- p = surface->Value( uv.X(), uv.Y() ).XYZ();
- }
- newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
- myLastCreatedNodes.Append(newN);
+ helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
}
// create a new element
if ( aBadRate1 <= aBadRate2 ) {
- 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] );
+ newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
+ newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
}
else {
- 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] );
+ newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
+ newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
}
} // quadratic case
// care of a new element
- myLastCreatedElems.Append(newElem1);
- myLastCreatedElems.Append(newElem2);
+ myLastCreatedElems.push_back(newElem1);
+ myLastCreatedElems.push_back(newElem2);
AddToSameGroups( newElem1, elem, aMesh );
AddToSameGroups( newElem2, elem, aMesh );
// put a new triangle on the same shape
if ( aShapeId )
- {
- aMesh->SetMeshElementOnShape( newElem1, aShapeId );
- aMesh->SetMeshElementOnShape( newElem2, aShapeId );
- }
+ aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+ aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+
aMesh->RemoveElement( elem );
}
return true;
}
//=======================================================================
-//function : BestSplit
-//purpose : Find better diagonal for cutting.
+/*!
+ * \brief Split each of given quadrangles into 4 triangles.
+ * \param theElems - The faces to be split. If empty all faces are split.
+ */
//=======================================================================
-int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
- SMESH::Controls::NumericalFunctorPtr theCrit)
+void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- if (!theCrit.get())
- return -1;
-
- if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
- return -1;
+ ClearLastCreated();
+ myLastCreatedElems.reserve( theElems.size() * 4 );
+
+ SMESH_MesherHelper helper( *GetMesh() );
+ helper.SetElementsOnShape( true );
+
+ // get standalone groups of faces
+ vector< SMDS_MeshGroup* > allFaceGroups, faceGroups;
+ for ( SMESHDS_GroupBase* grBase : GetMeshDS()->GetGroups() )
+ if ( SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( grBase ))
+ if ( group->GetType() == SMDSAbs_Face && !group->IsEmpty() )
+ allFaceGroups.push_back( & group->SMDSGroup() );
+
+ bool checkUV;
+ gp_XY uv [9]; uv[8] = gp_XY(0,0);
+ gp_XYZ xyz[9];
+ vector< const SMDS_MeshNode* > nodes;
+ SMESHDS_SubMesh* subMeshDS = 0;
+ TopoDS_Face F;
+ Handle(Geom_Surface) surface;
+ TopLoc_Location loc;
+
+ SMDS_ElemIteratorPtr faceIt;
+ if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
+ else faceIt = SMESHUtils::elemSetIterator( theElems );
+
+ while ( faceIt->more() )
+ {
+ const SMDS_MeshElement* quad = faceIt->next();
+ if ( !quad || quad->NbCornerNodes() != 4 )
+ continue;
- if( theQuad->NbNodes()==4 ||
- (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
+ // get a surface the quad is on
- // retrieve element nodes
- const SMDS_MeshNode* aNodes [4];
- SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
- int i = 0;
+ if ( quad->getshapeId() < 1 )
+ {
+ F.Nullify();
+ helper.SetSubShape( 0 );
+ subMeshDS = 0;
+ }
+ else if ( quad->getshapeId() != helper.GetSubShapeID() )
+ {
+ helper.SetSubShape( quad->getshapeId() );
+ if ( !helper.GetSubShape().IsNull() &&
+ helper.GetSubShape().ShapeType() == TopAbs_FACE )
+ {
+ F = TopoDS::Face( helper.GetSubShape() );
+ surface = BRep_Tool::Surface( F, loc );
+ subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
+ }
+ else
+ {
+ helper.SetSubShape( 0 );
+ subMeshDS = 0;
+ }
+ }
+
+ // create a central node
+
+ const SMDS_MeshNode* nCentral;
+ nodes.assign( quad->begin_nodes(), quad->end_nodes() );
+
+ if ( nodes.size() == 9 )
+ {
+ nCentral = nodes.back();
+ }
+ else
+ {
+ size_t iN = 0;
+ if ( F.IsNull() )
+ {
+ for ( ; iN < nodes.size(); ++iN )
+ xyz[ iN ] = SMESH_NodeXYZ( nodes[ iN ] );
+
+ for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
+ xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
+
+ xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
+ xyz[0], xyz[1], xyz[2], xyz[3],
+ xyz[4], xyz[5], xyz[6], xyz[7] );
+ }
+ else
+ {
+ for ( ; iN < nodes.size(); ++iN )
+ uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
+
+ for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
+ uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
+
+ uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
+ uv[0], uv[1], uv[2], uv[3],
+ uv[4], uv[5], uv[6], uv[7] );
+
+ gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
+ xyz[ 8 ] = p.XYZ();
+ }
+
+ nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
+ uv[8].X(), uv[8].Y() );
+ myLastCreatedNodes.push_back( nCentral );
+ }
+
+ helper.SetIsQuadratic ( nodes.size() > 4 );
+ helper.SetIsBiQuadratic( nodes.size() == 9 );
+ if ( helper.GetIsQuadratic() )
+ helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
+
+ // select groups to update
+ faceGroups.clear();
+ for ( SMDS_MeshGroup* group : allFaceGroups )
+ if ( group->Remove( quad ))
+ faceGroups.push_back( group );
+
+ // create 4 triangles
+
+ GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
+
+ for ( int i = 0; i < 4; ++i )
+ {
+ SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
+ nodes[(i+1)%4],
+ nCentral );
+ myLastCreatedElems.push_back( tria );
+ for ( SMDS_MeshGroup* group : faceGroups )
+ group->Add( tria );
+ }
+ }
+}
+
+//=======================================================================
+//function : BestSplit
+//purpose : Find better diagonal for cutting.
+//=======================================================================
+
+int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
+ SMESH::Controls::NumericalFunctorPtr theCrit)
+{
+ ClearLastCreated();
+
+ if (!theCrit.get())
+ return -1;
+
+ if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
+ return -1;
+
+ if( theQuad->NbNodes()==4 ||
+ (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
+
+ // retrieve element nodes
+ const SMDS_MeshNode* aNodes [4];
+ SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
+ int i = 0;
//while (itN->more())
while (i<4) {
aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
+ // Methods of splitting hexahedron into prisms
+
+ const int theHexTo4Prisms_BT[6*4+1] = // bottom-top
+ {
+ 0, 1, 8, 4, 5, 9, 1, 2, 8, 5, 6, 9, 2, 3, 8, 6, 7, 9, 3, 0, 8, 7, 4, 9, -1
+ };
+ const int theHexTo4Prisms_LR[6*4+1] = // left-right
+ {
+ 1, 0, 8, 2, 3, 9, 0, 4, 8, 3, 7, 9, 4, 5, 8, 7, 6, 9, 5, 1, 8, 6, 2, 9, -1
+ };
+ const int theHexTo4Prisms_FB[6*4+1] = // front-back
+ {
+ 0, 3, 9, 1, 2, 8, 3, 7, 9, 2, 6, 8, 7, 4, 9, 6, 5, 8, 4, 0, 9, 5, 1, 8, -1
+ };
+
+ const int theHexTo2Prisms_BT_1[6*2+1] =
+ {
+ 0, 1, 3, 4, 5, 7, 1, 2, 3, 5, 6, 7, -1
+ };
+ const int theHexTo2Prisms_BT_2[6*2+1] =
+ {
+ 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7, -1
+ };
+ const int* theHexTo2Prisms_BT[2] = { theHexTo2Prisms_BT_1, theHexTo2Prisms_BT_2 };
+
+ const int theHexTo2Prisms_LR_1[6*2+1] =
+ {
+ 1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1
+ };
+ const int theHexTo2Prisms_LR_2[6*2+1] =
+ {
+ 1, 0, 4, 2, 3, 7, 1, 4, 5, 2, 7, 6, -1
+ };
+ const int* theHexTo2Prisms_LR[2] = { theHexTo2Prisms_LR_1, theHexTo2Prisms_LR_2 };
+
+ const int theHexTo2Prisms_FB_1[6*2+1] =
+ {
+ 0, 3, 4, 1, 2, 5, 3, 7, 4, 2, 6, 5, -1
+ };
+ const int theHexTo2Prisms_FB_2[6*2+1] =
+ {
+ 0, 3, 7, 1, 2, 7, 0, 7, 4, 1, 6, 5, -1
+ };
+ const int* theHexTo2Prisms_FB[2] = { theHexTo2Prisms_FB_1, theHexTo2Prisms_FB_2 };
+
+
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;
+ bool hasAdjacentVol( const SMDS_MeshElement* elem,
+ const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const;
};
struct TSplitMethod
{
- int _nbTetra;
+ int _nbSplits;
+ int _nbCorners;
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) {}
+ : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
+ TSplitMethod(const TSplitMethod &splitMethod)
+ : _nbSplits(splitMethod._nbSplits),
+ _nbCorners(splitMethod._nbCorners),
+ _baryNode(splitMethod._baryNode),
+ _ownConn(splitMethod._ownConn),
+ _faceBaryNode(splitMethod._faceBaryNode)
+ {
+ _connectivity = splitMethod._connectivity;
+ const_cast<TSplitMethod&>(splitMethod)._connectivity = nullptr;
+ const_cast<TSplitMethod&>(splitMethod)._ownConn = false;
+ }
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;
+ if ( _nbCorners == 4 )
+ {
+ 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;
+ }
+ else // prism, _nbCorners == 6
+ {
+ const int* prismConn = _connectivity;
+ for ( ; prismConn[0] >= 0; prismConn += 6 )
+ {
+ if (( facet.contains( prismConn[0] ) &&
+ facet.contains( prismConn[1] ) &&
+ facet.contains( prismConn[2] ))
+ ||
+ ( facet.contains( prismConn[3] ) &&
+ facet.contains( prismConn[4] ) &&
+ facet.contains( prismConn[5] )))
+ return true;
+ }
+ }
return false;
}
};
//=======================================================================
/*!
- * \brief return TSplitMethod for the given element
+ * \brief return TSplitMethod for the given element to split into tetrahedra
*/
//=======================================================================
- TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
+ TSplitMethod getTetraSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
{
const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
{
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 );
+ if ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 );
+ else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 );
}
else
{
TTriangleFacet t023( nInd[ iQ * ( iCom )],
nInd[ iQ * ( (iCom+2)%nbNodes )],
nInd[ iQ * ( (iCom+3)%nbNodes )]);
- if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
+ if ( t012.hasAdjacentVol( vol.Element() ) && t023.hasAdjacentVol( vol.Element() ))
{
triaSplits.push_back( t012 );
triaSplits.push_back( t023 );
break;
case SMDSEntity_Penta:
case SMDSEntity_Quad_Penta:
+ case SMDSEntity_BiQuad_Penta:
connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
break;
default:
nbVariants = 0;
}
- for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
+ for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant )
{
- // check method compliancy with adjacent tetras,
+ // check method compliance 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 )
+ if ( hasAdjacentSplits && method._nbSplits > 0 )
{
bool facetCreated = true;
- for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
+ for ( size_t iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
{
list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
}
}
}
- if ( method._nbTetra < 1 )
+ if ( method._nbSplits < 1 )
{
// No standard method is applicable, use a generic solution:
// each facet of a volume is split into triangles and
connectivity[ connSize++ ] = baryCenInd;
}
}
- method._nbTetra += nbTet;
+ method._nbSplits += nbTet;
} // loop on volume faces
return method;
}
+ //=======================================================================
+ /*!
+ * \brief return TSplitMethod to split haxhedron into prisms
+ */
+ //=======================================================================
+
+ TSplitMethod getPrismSplitMethod( SMDS_VolumeTool& vol,
+ const int methodFlags,
+ const int facetToSplit)
+ {
+ TSplitMethod method;
+
+ // order of facets in HEX according to SMDS_VolumeTool::Hexa_F :
+ // B, T, L, B, R, F
+ const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2]
+
+ if ( methodFlags == SMESH_MeshEditor::HEXA_TO_4_PRISMS )
+ {
+ static TSplitMethod to4methods[4]; // order BT, LR, FB
+ if ( to4methods[iF]._nbSplits == 0 )
+ {
+ switch ( iF ) {
+ case 0:
+ to4methods[iF]._connectivity = theHexTo4Prisms_BT;
+ to4methods[iF]._faceBaryNode[ 0 ] = 0;
+ to4methods[iF]._faceBaryNode[ 1 ] = 0;
+ break;
+ case 1:
+ to4methods[iF]._connectivity = theHexTo4Prisms_LR;
+ to4methods[iF]._faceBaryNode[ 2 ] = 0;
+ to4methods[iF]._faceBaryNode[ 4 ] = 0;
+ break;
+ case 2:
+ to4methods[iF]._connectivity = theHexTo4Prisms_FB;
+ to4methods[iF]._faceBaryNode[ 3 ] = 0;
+ to4methods[iF]._faceBaryNode[ 5 ] = 0;
+ break;
+ default: return to4methods[3];
+ }
+ to4methods[iF]._nbSplits = 4;
+ to4methods[iF]._nbCorners = 6;
+ }
+ method = to4methods[iF];
+ to4methods[iF]._connectivity = method._connectivity; // as copy ctor resets _connectivity
+ return method;
+ }
+ // else if ( methodFlags == HEXA_TO_2_PRISMS )
+
+ const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
+
+ const int nbVariants = 2, nbSplits = 2;
+ const int** connVariants = 0;
+ switch ( iF ) {
+ case 0: connVariants = theHexTo2Prisms_BT; break;
+ case 1: connVariants = theHexTo2Prisms_LR; break;
+ case 2: connVariants = theHexTo2Prisms_FB; break;
+ default: return method;
+ }
+
+ // look for prisms adjacent via facetToSplit and an opposite one
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
+ int nbNodes = vol.NbFaceNodes( iFacet ) / iQ;
+ if ( nbNodes != 4 ) return method;
+
+ const int* nInd = vol.GetFaceNodesIndices( iFacet );
+ TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
+ TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
+ TTriangleFacet* t;
+ if ( t012.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
+ t = &t012;
+ else if ( t123.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
+ t = &t123;
+ else
+ continue;
+
+ // there are adjacent prism
+ for ( int variant = 0; variant < nbVariants; ++variant )
+ {
+ // check method compliance with adjacent prisms,
+ // the found prism facets must be among facets of prisms described by current method
+ method._nbSplits = nbSplits;
+ method._nbCorners = 6;
+ method._connectivity = connVariants[ variant ];
+ if ( method.hasFacet( *t ))
+ return method;
+ }
+ }
+
+ // No adjacent prisms. Select a variant with a best aspect ratio.
+
+ double badness[2] = { 0., 0. };
+ static SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
+ const SMDS_MeshNode** nodes = vol.GetNodes();
+ for ( int variant = 0; variant < nbVariants; ++variant )
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
+ const int* nInd = vol.GetFaceNodesIndices( iFacet );
+
+ method._connectivity = connVariants[ variant ];
+ TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
+ TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
+ TTriangleFacet* t = ( method.hasFacet( t012 )) ? & t012 : & t123;
+
+ SMDS_FaceOfNodes tria ( nodes[ t->_n1 ],
+ nodes[ t->_n2 ],
+ nodes[ t->_n3 ] );
+ badness[ variant ] += getBadRate( &tria, aspectRatio );
+ }
+ const int iBetter = ( badness[1] < badness[0] && badness[0]-badness[1] > 0.1 * badness[0] );
+
+ method._nbSplits = nbSplits;
+ method._nbCorners = 6;
+ method._connectivity = connVariants[ iBetter ];
+
+ 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
+ bool TTriangleFacet::hasAdjacentVol( const SMDS_MeshElement* elem,
+ const SMDSAbs_GeometryType geom ) const
{
// find the tetrahedron including the three nodes of facet
const SMDS_MeshNode* n1 = elem->GetNode(_n1);
while ( volIt1->more() )
{
const SMDS_MeshElement* v = volIt1->next();
- SMDSAbs_EntityType type = v->GetEntityType();
- if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
+ if ( v->GetGeomType() != geom )
continue;
- if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
+ const int lastCornerInd = v->NbCornerNodes() - 1;
+ if ( v->IsQuadratic() && v->GetNodeIndex( n1 ) > lastCornerInd )
continue; // medium node not allowed
const int ind2 = v->GetNodeIndex( n2 );
- if ( ind2 < 0 || 3 < ind2 )
+ if ( ind2 < 0 || lastCornerInd < ind2 )
continue;
const int ind3 = v->GetNodeIndex( n3 );
- if ( ind3 < 0 || 3 < ind3 )
+ if ( ind3 < 0 || lastCornerInd < ind3 )
continue;
return true;
}
*/
//=======================================================================
- struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
+ struct TVolumeFaceKey: pair< pair< smIdType, smIdType>, pair< smIdType, smIdType> >
{
TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
{
} // namespace
//=======================================================================
-//function : SplitVolumesIntoTetra
-//purpose : Split volume elements into tetrahedra.
+//function : SplitVolumes
+//purpose : Split volume elements into tetrahedra or prisms.
+// If facet ID < 0, element is split into tetrahedra,
+// else a hexahedron is split into prisms so that the given facet is
+// split into triangles
//=======================================================================
-void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
- const int theMethodFlags)
+void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
+ const int theMethodFlags)
{
- // std-like iterator on coordinates of nodes of mesh element
- typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
- NXyzIterator xyzEnd;
-
SMDS_VolumeTool volTool;
- SMESH_MesherHelper helper( *GetMesh());
+ SMESH_MesherHelper helper( *GetMesh()), fHelper(*GetMesh());
+ fHelper.ToFixNodeParameters( true );
SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
// map face of volume to it's baricenrtic node
map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
double bc[3];
+ vector<const SMDS_MeshElement* > splitVols;
- TIDSortedElemSet::const_iterator elem = theElems.begin();
- for ( ; elem != theElems.end(); ++elem )
+ TFacetOfElem::const_iterator elem2facet = theElems.begin();
+ for ( ; elem2facet != theElems.end(); ++elem2facet )
{
- if ( (*elem)->GetType() != SMDSAbs_Volume )
+ const SMDS_MeshElement* elem = elem2facet->first;
+ const int facetToSplit = elem2facet->second;
+ if ( elem->GetType() != SMDSAbs_Volume )
continue;
- SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
+ const SMDSAbs_EntityType geomType = elem->GetEntityType();
if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
continue;
- if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
+ if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange...
- TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
- if ( splitMethod._nbTetra < 1 ) continue;
+ TSplitMethod splitMethod = ( facetToSplit < 0 ?
+ getTetraSplitMethod( volTool, theMethodFlags ) :
+ getPrismSplitMethod( volTool, theMethodFlags, facetToSplit ));
+ if ( splitMethod._nbSplits < 1 ) continue;
// find submesh to add new tetras to
- if ( !subMesh || !subMesh->Contains( *elem ))
+ if ( !subMesh || !subMesh->Contains( elem ))
{
- int shapeID = FindShape( *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() )
+ if ( elem->IsQuadratic() )
{
iQ = 2;
// add quadratic links to the helper
iQ = 1;
helper.SetIsQuadratic( false );
}
- vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
+ vector<const SMDS_MeshNode*> nodes( volTool.GetNodes(),
+ volTool.GetNodes() + elem->NbNodes() );
helper.SetElementsOnShape( true );
if ( splitMethod._baryNode )
{
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 );
+ newNodes.push_back( gcNode );
}
if ( !splitMethod._faceBaryNode.empty() )
{
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] ));
+ newNodes.push_back( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
}
nodes.push_back( iF_n->second = f_n->second );
}
}
- // make tetras
- 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] ]));
+ // make new volumes
+ splitVols.resize( splitMethod._nbSplits ); // splits of a volume
+ const int* volConn = splitMethod._connectivity;
+ if ( splitMethod._nbCorners == 4 ) // tetra
+ for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
+ newElems.push_back( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
+ nodes[ volConn[1] ],
+ nodes[ volConn[2] ],
+ nodes[ volConn[3] ]));
+ else // prisms
+ for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
+ newElems.push_back( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
+ nodes[ volConn[1] ],
+ nodes[ volConn[2] ],
+ nodes[ volConn[3] ],
+ nodes[ volConn[4] ],
+ nodes[ volConn[5] ]));
- ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
+ ReplaceElemInGroups( elem, splitVols, GetMeshDS() );
// Split faces on sides of the split volume
map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
if ( iF_n != splitMethod._faceBaryNode.end() )
{
+ const SMDS_MeshNode *baryNode = iF_n->second;
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;
+ const SMDS_MeshNode *n3 = baryNode;
if ( !volTool.IsFaceExternal( iF ))
swap( n2, n3 );
triangles.push_back( helper.AddFace( n1,n2,n3 ));
-
- if ( fSubMesh && n3->getshapeId() < 1 )
- fSubMesh->AddNode( n3 );
+ }
+ if ( fSubMesh ) // update position of the bary node on geometry
+ {
+ if ( subMesh )
+ subMesh->RemoveNode( baryNode );
+ GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() );
+ const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() );
+ if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE )
+ {
+ fHelper.SetSubShape( s );
+ gp_XY uv( 1e100, 1e100 );
+ double distXYZ[4];
+ if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode,
+ uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) &&
+ uv.X() < 1e100 )
+ {
+ // node is too far from the surface
+ GetMeshDS()->MoveNode( baryNode, distXYZ[1], distXYZ[2], distXYZ[3] );
+ const_cast<SMDS_MeshNode*>( baryNode )->SetPosition
+ ( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() )));
+ }
+ }
}
}
else
{
- // among possible triangles create ones discribed by split method
+ // among possible triangles create ones described 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 >::iterator facet = facets.begin();
+ if ( facet == facets.end() )
+ break;
for ( ; facet != facets.end(); ++facet )
{
if ( !volTool.IsFaceExternal( iF ))
volNodes[ facet->_n3 ]));
}
}
- for ( int i = 0; i < triangles.size(); ++i )
+ for ( size_t i = 0; i < triangles.size(); ++i )
{
- if ( !triangles[i] ) continue;
+ if ( !triangles[ i ]) continue;
if ( fSubMesh )
- fSubMesh->AddElement( triangles[i]);
- newElems.Append( triangles[i] );
+ fSubMesh->AddElement( triangles[ i ]);
+ newElems.push_back( triangles[ i ]);
}
ReplaceElemInGroups( face, triangles, GetMeshDS() );
GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
- }
+ } // while a face based on facet nodes exists
} // loop on volume faces to split them into triangles
- GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
+ GetMeshDS()->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
if ( geomType == SMDSEntity_TriQuad_Hexa )
{
}
//=======================================================================
-//function : AddToSameGroups
-//purpose : add elemToAdd to the groups the elemInGroups belongs to
+//function : GetHexaFacetsToSplit
+//purpose : For hexahedra that will be split into prisms, finds facets to
+// split into triangles. Only hexahedra adjacent to the one closest
+// to theFacetNormal.Location() are returned.
+//param [in,out] theHexas - the hexahedra
+//param [in] theFacetNormal - facet normal
+//param [out] theFacets - the hexahedra and found facet IDs
//=======================================================================
-void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
- const SMDS_MeshElement* elemInGroups,
- SMESHDS_Mesh * aMesh)
+void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
+ const gp_Ax1& theFacetNormal,
+ TFacetOfElem & theFacets)
{
- 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 );
- }
- }
-}
+#define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): "
+ // Find a hexa closest to the location of theFacetNormal
-//=======================================================================
-//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())
+ const SMDS_MeshElement* startHex;
{
- 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);
- }
- }
-}
+ // get SMDS_ElemIteratorPtr on theHexas
+ typedef const SMDS_MeshElement* TValue;
+ typedef TIDSortedElemSet::iterator TSetIterator;
+ typedef SMDS::SimpleAccessor<TValue,TSetIterator> TAccesor;
+ typedef SMDS_MeshElement::GeomFilter TFilter;
+ typedef SMDS_SetIterator < TValue, TSetIterator, TAccesor, TFilter > TElemSetIter;
+ SMDS_ElemIteratorPtr elemIt = SMDS_ElemIteratorPtr
+ ( new TElemSetIter( theHexas.begin(),
+ theHexas.end(),
+ SMDS_MeshElement::GeomFilter( SMDSGeom_HEXA )));
-//================================================================================
-/*!
- * \brief Replace elemToRm by elemToAdd in the all groups
- */
-//================================================================================
+ SMESH_ElementSearcher* searcher =
+ SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS(), elemIt );
-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 );
- }
+ startHex = searcher->FindClosestTo( theFacetNormal.Location(), SMDSAbs_Volume );
+
+ delete searcher;
+
+ if ( !startHex )
+ throw SALOME_Exception( THIS_METHOD "startHex not found");
}
-}
-//================================================================================
-/*!
- * \brief Replace elemToRm by elemToAdd in the all groups
- */
-//================================================================================
+ // Select a facet of startHex by theFacetNormal
-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 ] );
+ SMDS_VolumeTool vTool( startHex );
+ double norm[3], dot, maxDot = 0;
+ int facetID = -1;
+ for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
+ if ( vTool.GetFaceNormal( iF, norm[0], norm[1], norm[2] ))
+ {
+ dot = Abs( theFacetNormal.Direction().Dot( gp_Dir( norm[0], norm[1], norm[2] )));
+ if ( dot > maxDot )
+ {
+ facetID = iF;
+ maxDot = dot;
+ }
}
- }
-}
+ if ( facetID < 0 )
+ throw SALOME_Exception( THIS_METHOD "facet of startHex not found");
-//=======================================================================
-//function : QuadToTri
-//purpose : Cut quadrangles into triangles.
-// theCrit is used to select a diagonal to cut
-//=======================================================================
+ // Fill theFacets starting from facetID of startHex
-bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
- const bool the13Diag)
-{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ // facets used for searching of volumes adjacent to already treated ones
+ typedef pair< TFacetOfElem::iterator, int > TElemFacets;
+ typedef map< TVolumeFaceKey, TElemFacets > TFacetMap;
+ TFacetMap facetsToCheck;
- MESSAGE( "::QuadToTri()" );
+ set<const SMDS_MeshNode*> facetNodes;
+ const SMDS_MeshElement* curHex;
- SMESHDS_Mesh * aMesh = GetMeshDS();
+ const bool allHex = ((int) theHexas.size() == myMesh->NbHexas() );
- Handle(Geom_Surface) surface;
- SMESH_MesherHelper helper( *GetMesh() );
+ while ( startHex )
+ {
+ // move in two directions from startHex via facetID
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ curHex = startHex;
+ int curFacet = facetID;
+ if ( is2nd ) // do not treat startHex twice
+ {
+ vTool.Set( curHex );
+ if ( vTool.IsFreeFace( curFacet, &curHex ))
+ {
+ curHex = 0;
+ }
+ else
+ {
+ vTool.GetFaceNodes( curFacet, facetNodes );
+ vTool.Set( curHex );
+ curFacet = vTool.GetFaceIndex( facetNodes );
+ }
+ }
+ while ( curHex )
+ {
+ // store a facet to split
+ if ( curHex->GetGeomType() != SMDSGeom_HEXA )
+ {
+ theFacets.insert( make_pair( curHex, -1 ));
+ break;
+ }
+ if ( !allHex && !theHexas.count( curHex ))
+ break;
- 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;
+ pair< TFacetOfElem::iterator, bool > facetIt2isNew =
+ theFacets.insert( make_pair( curHex, curFacet ));
+ if ( !facetIt2isNew.second )
+ break;
- if(elem->NbNodes()==4) {
- // retrieve element nodes
- const SMDS_MeshNode* aNodes [4];
+ // remember not-to-split facets in facetsToCheck
+ int oppFacet = vTool.GetOppFaceIndexOfHex( curFacet );
+ for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
+ {
+ if ( iF == curFacet && iF == oppFacet )
+ continue;
+ TVolumeFaceKey facetKey ( vTool, iF );
+ TElemFacets elemFacet( facetIt2isNew.first, iF );
+ pair< TFacetMap::iterator, bool > it2isnew =
+ facetsToCheck.insert( make_pair( facetKey, elemFacet ));
+ if ( !it2isnew.second )
+ facetsToCheck.erase( it2isnew.first ); // adjacent hex already checked
+ }
+ // pass to a volume adjacent via oppFacet
+ if ( vTool.IsFreeFace( oppFacet, &curHex ))
+ {
+ curHex = 0;
+ }
+ else
+ {
+ // get a new curFacet
+ vTool.GetFaceNodes( oppFacet, facetNodes );
+ vTool.Set( curHex );
+ curFacet = vTool.GetFaceIndex( facetNodes, /*hint=*/curFacet );
+ }
+ }
+ } // move in two directions from startHex via facetID
+
+ // Find a new startHex by facetsToCheck
+
+ startHex = 0;
+ facetID = -1;
+ TFacetMap::iterator fIt = facetsToCheck.begin();
+ while ( !startHex && fIt != facetsToCheck.end() )
+ {
+ const TElemFacets& elemFacets = fIt->second;
+ const SMDS_MeshElement* hex = elemFacets.first->first;
+ int splitFacet = elemFacets.first->second;
+ int lateralFacet = elemFacets.second;
+ facetsToCheck.erase( fIt );
+ fIt = facetsToCheck.begin();
+
+ vTool.Set( hex );
+ if ( vTool.IsFreeFace( lateralFacet, &curHex ) ||
+ curHex->GetGeomType() != SMDSGeom_HEXA )
+ continue;
+ if ( !allHex && !theHexas.count( curHex ))
+ continue;
+
+ startHex = curHex;
+
+ // find a facet of startHex to split
+
+ set<const SMDS_MeshNode*> lateralNodes;
+ vTool.GetFaceNodes( lateralFacet, lateralNodes );
+ vTool.GetFaceNodes( splitFacet, facetNodes );
+ int oppLateralFacet = vTool.GetOppFaceIndexOfHex( lateralFacet );
+ vTool.Set( startHex );
+ lateralFacet = vTool.GetFaceIndex( lateralNodes, oppLateralFacet );
+
+ // look for a facet of startHex having common nodes with facetNodes
+ // but not lateralFacet
+ for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
+ {
+ if ( iF == lateralFacet )
+ continue;
+ int nbCommonNodes = 0;
+ const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF );
+ for ( int iN = 0, nbN = vTool.NbFaceNodes( iF ); iN < nbN; ++iN )
+ nbCommonNodes += facetNodes.count( nn[ iN ]);
+
+ if ( nbCommonNodes >= 2 )
+ {
+ facetID = iF;
+ break;
+ }
+ }
+ if ( facetID < 0 )
+ throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found");
+ }
+ } // while ( startHex )
+
+ return;
+}
+
+namespace
+{
+ //================================================================================
+ /*!
+ * \brief Selects nodes of several elements according to a given interlace
+ * \param [in] srcNodes - nodes to select from
+ * \param [out] tgtNodesVec - array of nodes of several elements to fill in
+ * \param [in] interlace - indices of nodes for all elements
+ * \param [in] nbElems - nb of elements
+ * \param [in] nbNodes - nb of nodes in each element
+ * \param [in] mesh - the mesh
+ * \param [out] elemQueue - a list to push elements found by the selected nodes
+ * \param [in] type - type of elements to look for
+ */
+ //================================================================================
+
+ void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes,
+ vector< const SMDS_MeshNode* >* tgtNodesVec,
+ const int* interlace,
+ const int nbElems,
+ const int nbNodes,
+ SMESHDS_Mesh* mesh = 0,
+ list< const SMDS_MeshElement* >* elemQueue=0,
+ SMDSAbs_ElementType type=SMDSAbs_All)
+ {
+ for ( int iE = 0; iE < nbElems; ++iE )
+ {
+ vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE];
+ const int* select = & interlace[iE*nbNodes];
+ elemNodes.resize( nbNodes );
+ for ( int iN = 0; iN < nbNodes; ++iN )
+ elemNodes[iN] = srcNodes[ select[ iN ]];
+ }
+ const SMDS_MeshElement* e;
+ if ( elemQueue )
+ for ( int iE = 0; iE < nbElems; ++iE )
+ if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false)))
+ elemQueue->push_back( e );
+ }
+}
+
+//=======================================================================
+/*
+ * Split bi-quadratic elements into linear ones without creation of additional nodes
+ * - bi-quadratic triangle will be split into 3 linear quadrangles;
+ * - bi-quadratic quadrangle will be split into 4 linear quadrangles;
+ * - tri-quadratic hexahedron will be split into 8 linear hexahedra;
+ * Quadratic elements of lower dimension adjacent to the split bi-quadratic element
+ * will be split in order to keep the mesh conformal.
+ * \param elems - elements to split
+ */
+//=======================================================================
+
+void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems)
+{
+ vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8];
+ vector<const SMDS_MeshElement* > splitElems;
+ list< const SMDS_MeshElement* > elemQueue;
+ list< const SMDS_MeshElement* >::iterator elemIt;
+
+ SMESHDS_Mesh * mesh = GetMeshDS();
+ ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge);
+ int nbElems, nbNodes;
+
+ TIDSortedElemSet::iterator elemSetIt = theElems.begin();
+ for ( ; elemSetIt != theElems.end(); ++elemSetIt )
+ {
+ elemQueue.clear();
+ elemQueue.push_back( *elemSetIt );
+ for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt )
+ {
+ const SMDS_MeshElement* elem = *elemIt;
+ switch( elem->GetEntityType() )
+ {
+ case SMDSEntity_TriQuad_Hexa: // HEX27
+ {
+ elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+ nbElems = nbNodes = 8;
+ elemType = & hexaType;
+
+ // get nodes for new elements
+ static int vInd[8][8] = {{ 0,8,20,11, 16,21,26,24 },
+ { 1,9,20,8, 17,22,26,21 },
+ { 2,10,20,9, 18,23,26,22 },
+ { 3,11,20,10, 19,24,26,23 },
+ { 16,21,26,24, 4,12,25,15 },
+ { 17,22,26,21, 5,13,25,12 },
+ { 18,23,26,22, 6,14,25,13 },
+ { 19,24,26,23, 7,15,25,14 }};
+ selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes );
+
+ // add boundary faces to elemQueue
+ static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11, 20 },
+ { 4,5,6,7, 12,13,14,15, 25 },
+ { 0,1,5,4, 8,17,12,16, 21 },
+ { 1,2,6,5, 9,18,13,17, 22 },
+ { 2,3,7,6, 10,19,14,18, 23 },
+ { 3,0,4,7, 11,16,15,19, 24 }};
+ selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face );
+
+ // add boundary segments to elemQueue
+ static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 },
+ { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 },
+ { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }};
+ selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge );
+ break;
+ }
+ case SMDSEntity_BiQuad_Triangle: // TRIA7
+ {
+ elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+ nbElems = 3;
+ nbNodes = 4;
+ elemType = & quadType;
+
+ // get nodes for new elements
+ static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }};
+ selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
+
+ // add boundary segments to elemQueue
+ static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }};
+ selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge );
+ break;
+ }
+ case SMDSEntity_BiQuad_Quadrangle: // QUAD9
+ {
+ elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+ nbElems = 4;
+ nbNodes = 4;
+ elemType = & quadType;
+
+ // get nodes for new elements
+ static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }};
+ selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
+
+ // add boundary segments to elemQueue
+ static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }};
+ selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge );
+ break;
+ }
+ case SMDSEntity_Quad_Edge:
+ {
+ if ( elemIt == elemQueue.begin() )
+ continue; // an elem is in theElems
+ elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
+ nbElems = 2;
+ nbNodes = 2;
+ elemType = & segType;
+
+ // get nodes for new elements
+ static int eInd[2][2] = {{ 0,2 }, { 2,1 }};
+ selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes );
+ break;
+ }
+ default: continue;
+ } // switch( elem->GetEntityType() )
+
+ // Create new elements
+
+ SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() );
+
+ splitElems.clear();
+
+ //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one
+ mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
+ //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType ));
+ //elemType->SetID( -1 );
+
+ for ( int iE = 0; iE < nbElems; ++iE )
+ splitElems.push_back( AddElement( splitNodes[ iE ], *elemType ));
+
+
+ ReplaceElemInGroups( elem, splitElems, mesh );
+
+ if ( subMesh )
+ for ( size_t i = 0; i < splitElems.size(); ++i )
+ subMesh->AddElement( splitElems[i] );
+ }
+ }
+}
+
+//=======================================================================
+//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 ( size_t 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)
+{
+ ClearLastCreated();
+ myLastCreatedElems.reserve( theElems.size() * 2 );
+
+ 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->GetGeomType() != SMDSGeom_QUADRANGLE )
+ continue;
+
+ if ( elem->NbNodes() == 4 ) {
+ // retrieve element nodes
+ const SMDS_MeshNode* aNodes [4];
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
int i = 0;
while ( itN->more() )
newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
}
- myLastCreatedElems.Append(newElem1);
- myLastCreatedElems.Append(newElem2);
+ myLastCreatedElems.push_back(newElem1);
+ myLastCreatedElems.push_back(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 );
- }
+ {
+ 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() ) {
-
+ else if ( elem->NbNodes() >= 8 )
+ {
// get surface elem is on
int aShapeId = FindShape( elem );
if ( aShapeId != helper.GetSubShapeID() ) {
}
}
- const SMDS_MeshNode* aNodes [8];
- const SMDS_MeshNode* inFaceNode = 0;
+ const SMDS_MeshNode* aNodes [9]; aNodes[8] = 0;
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- int i = 0;
- while ( itN->more() ) {
- aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
- if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
- aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
- {
- inFaceNode = aNodes[ i-1 ];
- }
- }
+ for ( int i = 0; itN->more(); ++i )
+ aNodes[ i ] = static_cast<const SMDS_MeshNode*>( itN->next() );
- // find middle point for (0,1,2,3)
- // and create a node in this point;
- gp_XYZ p( 0,0,0 );
- if ( surface.IsNull() ) {
- for(i=0; i<4; i++)
- p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
- p /= 4;
- }
- else {
- TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
- gp_XY uv( 0,0 );
- for(i=0; i<4; i++)
- uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
- uv /= 4.;
- p = surface->Value( uv.X(), uv.Y() ).XYZ();
+ const SMDS_MeshNode* centrNode = aNodes[8];
+ if ( centrNode == 0 )
+ {
+ centrNode = helper.GetCentralNode( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+ aNodes[4], aNodes[5], aNodes[6], aNodes[7],
+ surface.IsNull() );
+ myLastCreatedNodes.push_back(centrNode);
}
- const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
- myLastCreatedNodes.Append(newN);
// create a new element
const SMDS_MeshElement* newElem1 = 0;
const SMDS_MeshElement* newElem2 = 0;
if ( the13Diag ) {
newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
- aNodes[6], aNodes[7], newN );
+ aNodes[6], aNodes[7], centrNode );
newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
- newN, aNodes[4], aNodes[5] );
+ centrNode, aNodes[4], aNodes[5] );
}
else {
newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
- aNodes[7], aNodes[4], newN );
+ aNodes[7], aNodes[4], centrNode );
newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
- newN, aNodes[5], aNodes[6] );
+ centrNode, aNodes[5], aNodes[6] );
}
- myLastCreatedElems.Append(newElem1);
- myLastCreatedElems.Append(newElem2);
+ myLastCreatedElems.push_back(newElem1);
+ myLastCreatedElems.push_back(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 );
- }
+ {
+ aMesh->SetMeshElementOnShape( newElem1, aShapeId );
+ aMesh->SetMeshElementOnShape( newElem2, aShapeId );
+ }
AddToSameGroups( newElem1, elem, aMesh );
AddToSameGroups( newElem2, elem, aMesh );
aMesh->RemoveElement( elem );
:myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
{}
- long GetLinkID (const SMDS_MeshNode * n1,
+ smIdType GetLinkID (const SMDS_MeshNode * n1,
const SMDS_MeshNode * n2) const
{
- return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
+ return ( std::min(n1->GetID(),n2->GetID()) * myMaxID + std::max(n1->GetID(),n2->GetID()));
}
bool GetNodes (const long theLinkID,
SMESH::Controls::NumericalFunctorPtr theCrit,
const double theMaxAngle)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- MESSAGE( "::TriToQuad()" );
+ ClearLastCreated();
+ myLastCreatedElems.reserve( theElems.size() / 2 );
if ( !theCrit.get() )
return false;
map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
TIDSortedElemSet::iterator itElem;
- for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+ {
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;
+ bool IsTria = ( elem->NbCornerNodes()==3 );
+ if (!IsTria) continue;
// retrieve element nodes
const SMDS_MeshNode* aNodes [4];
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ SMDS_NodeIteratorPtr itN = elem->nodeIterator();
int i = 0;
- while ( i<3 )
- aNodes[ i++ ] = cast2Node( itN->next() );
+ while ( i < 3 )
+ aNodes[ i++ ] = itN->next();
aNodes[ 3 ] = aNodes[ 0 ];
// fill maps
if ( startElem ) {
// Get candidates to be fused
const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
- const SMESH_TLink *link12, *link13;
+ const SMESH_TLink *link12 = 0, *link13 = 0;
startElem = 0;
ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
}
// Make quadrangles
- // and remove fused elems and removed links from the maps
+ // and remove fused elems and remove links from the maps
mapEl_setLi.erase( tr1 );
- if ( Ok12 ) {
+ if ( Ok12 )
+ {
mapEl_setLi.erase( tr2 );
mapLi_listEl.erase( *link12 );
- if(tr1->NbNodes()==3) {
+ if ( tr1->NbNodes() == 3 )
+ {
const SMDS_MeshElement* newElem = 0;
newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
- myLastCreatedElems.Append(newElem);
+ myLastCreatedElems.push_back(newElem);
AddToSameGroups( newElem, tr1, aMesh );
int aShapeId = tr1->getshapeId();
if ( aShapeId )
- {
- aMesh->SetMeshElementOnShape( newElem, 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)
+ vector< const SMDS_MeshNode* > N1;
+ vector< const SMDS_MeshNode* > N2;
+ getNodesFromTwoTria(tr1,tr2,N1,N2);
+ // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
// 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
+ // i.e. first nodes from both arrays form a new diagonal
const SMDS_MeshNode* aNodes[8];
aNodes[0] = N1[0];
aNodes[1] = N1[1];
aNodes[6] = N2[3];
aNodes[7] = N1[5];
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);
+ if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
+ newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+ aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
+ else
+ newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+ aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+ myLastCreatedElems.push_back(newElem);
AddToSameGroups( newElem, tr1, aMesh );
int aShapeId = tr1->getshapeId();
if ( aShapeId )
- {
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- }
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
aMesh->RemoveElement( tr1 );
aMesh->RemoveElement( tr2 );
// remove middle node (9)
- GetMeshDS()->RemoveNode( N1[4] );
+ if ( N1[4]->NbInverseElements() == 0 )
+ aMesh->RemoveNode( N1[4] );
+ if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
+ aMesh->RemoveNode( N1[6] );
+ if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
+ aMesh->RemoveNode( N2[6] );
}
}
- else if ( Ok13 ) {
+ else if ( Ok13 )
+ {
mapEl_setLi.erase( tr3 );
mapLi_listEl.erase( *link13 );
- if(tr1->NbNodes()==3) {
+ if ( tr1->NbNodes() == 3 ) {
const SMDS_MeshElement* newElem = 0;
newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
- myLastCreatedElems.Append(newElem);
+ myLastCreatedElems.push_back(newElem);
AddToSameGroups( newElem, tr1, aMesh );
int aShapeId = tr1->getshapeId();
if ( aShapeId )
- {
- aMesh->SetMeshElementOnShape( newElem, 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);
+ vector< const SMDS_MeshNode* > N1;
+ vector< const SMDS_MeshNode* > N2;
+ 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)
- // i.e. first nodes from both arrays determ new diagonal
+ // i.e. first nodes from both arrays form a new diagonal
const SMDS_MeshNode* aNodes[8];
aNodes[0] = N1[0];
aNodes[1] = N1[1];
aNodes[6] = N2[3];
aNodes[7] = N1[5];
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);
+ if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
+ newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+ aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
+ else
+ newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
+ aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
+ myLastCreatedElems.push_back(newElem);
AddToSameGroups( newElem, tr1, aMesh );
int aShapeId = tr1->getshapeId();
if ( aShapeId )
- {
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- }
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
aMesh->RemoveElement( tr1 );
aMesh->RemoveElement( tr3 );
// remove middle node (9)
- GetMeshDS()->RemoveNode( N1[4] );
+ if ( N1[4]->NbInverseElements() == 0 )
+ aMesh->RemoveNode( N1[4] );
+ if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
+ aMesh->RemoveNode( N1[6] );
+ if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
+ aMesh->RemoveNode( N2[6] );
}
}
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
+ */
+//================================================================================
-/*#define DUMPSO(txt) \
-// cout << txt << endl;
-//=============================================================================
-//
-//
-//
-//=============================================================================
-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 ] << ")");
-}
-
-//=======================================================================
-//function : SortQuadNodes
-//purpose : Set 4 nodes of a quadrangle face in a good order.
-// Swap 1<->2 or 2<->3 nodes and correspondingly return
-// 1 or 2 else 0.
-//=======================================================================
-
-int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
-int idNodes[] )
+void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
+ TIDSortedElemSet & linkedNodes,
+ SMDSAbs_ElementType type )
{
- gp_Pnt P[4];
- int i;
- for ( i = 0; i < 4; i++ ) {
- const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
- if ( !n ) return 0;
- P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
- }
-
- gp_Vec V1(P[0], P[1]);
- gp_Vec V2(P[0], P[2]);
- gp_Vec V3(P[0], P[3]);
-
- gp_Vec Cross1 = V1 ^ V2;
- gp_Vec Cross2 = V2 ^ V3;
-
- i = 0;
- if (Cross1.Dot(Cross2) < 0)
- {
- Cross1 = V2 ^ V1;
- Cross2 = V1 ^ V3;
-
- if (Cross1.Dot(Cross2) < 0)
- i = 2;
- else
- 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());
- // }
- }
- return i;
-}
-
-//=======================================================================
-//function : SortHexaNodes
-//purpose : Set 8 nodes of a hexahedron in a good order.
-// Return success status
-//=======================================================================
-
-bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
- int idNodes[] )
-{
- gp_Pnt P[8];
- int i;
- DUMPSO( "INPUT: ========================================");
- for ( i = 0; i < 8; i++ ) {
- const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
- if ( !n ) return false;
- P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
- DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
- }
- DUMPSO( "========================================");
-
-
- set<int> faceNodes; // ids of bottom face nodes, to be found
- set<int> checkedId1; // ids of tried 2-nd nodes
- Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
- const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
- int iMin, iLoop1 = 0;
-
- // Loop to try the 2-nd nodes
-
- while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
- {
- // Find not checked 2-nd node
- for ( i = 1; i < 8; i++ )
- if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
- int id1 = idNodes[i];
- swap ( 1, i, idNodes, P );
- checkedId1.insert ( id1 );
- break;
- }
-
- // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
- // ie that all but meybe one (id3 which is on the same face) nodes
- // lay on the same side from the triangle plane.
-
- bool manyInPlane = false; // more than 4 nodes lay in plane
- int iLoop2 = 0;
- while ( ++iLoop2 < 6 ) {
-
- // get 1-2-3 plane coeffs
- Standard_Real A, B, C, D;
- gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
- if ( N.SquareMagnitude() > gp::Resolution() )
- {
- gp_Pln pln ( P[0], N );
- pln.Coefficients( A, B, C, D );
-
- // find the node (iMin) closest to pln
- Standard_Real dist[ 8 ], minDist = DBL_MAX;
- set<int> idInPln;
- for ( i = 3; i < 8; i++ ) {
- dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
- if ( fabs( dist[i] ) < minDist ) {
- minDist = fabs( dist[i] );
- iMin = i;
- }
- if ( fabs( dist[i] ) <= tol )
- idInPln.insert( idNodes[i] );
- }
-
- // there should not be more than 4 nodes in bottom plane
- if ( idInPln.size() > 1 )
- {
- DUMPSO( "### idInPln.size() = " << idInPln.size());
- // idInPlane does not contain the first 3 nodes
- if ( manyInPlane || idInPln.size() == 5)
- return false; // all nodes in one plane
- manyInPlane = true;
-
- // set the 1-st node to be not in plane
- for ( i = 3; i < 8; i++ ) {
- if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
- DUMPSO( "### Reset 0-th node");
- swap( 0, i, idNodes, P );
- break;
- }
- }
-
- // reset to re-check second nodes
- leastDist = DBL_MAX;
- faceNodes.clear();
- checkedId1.clear();
- iLoop1 = 0;
- break; // from iLoop2;
- }
-
- // check that the other 4 nodes are on the same side
- bool sameSide = true;
- bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
- for ( i = 3; sameSide && i < 8; i++ ) {
- if ( i != iMin )
- sameSide = ( isNeg == dist[i] <= 0.);
- }
-
- // keep best solution
- if ( sameSide && minDist < leastDist ) {
- leastDist = minDist;
- faceNodes.clear();
- faceNodes.insert( idNodes[ 1 ] );
- faceNodes.insert( idNodes[ 2 ] );
- faceNodes.insert( idNodes[ iMin ] );
- DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
- << " leastDist = " << leastDist);
- if ( leastDist <= DBL_MIN )
- break;
- }
- }
-
- // set next 3-d node to check
- int iNext = 2 + iLoop2;
- if ( iNext < 8 ) {
- DUMPSO( "Try 2-nd");
- swap ( 2, iNext, idNodes, P );
- }
- } // while ( iLoop2 < 6 )
- } // iLoop1
-
- if ( faceNodes.empty() ) return false;
-
- // Put the faceNodes in proper places
- for ( i = 4; i < 8; i++ ) {
- if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
- // find a place to put
- int iTo = 1;
- while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
- iTo++;
- DUMPSO( "Set faceNodes");
- swap ( iTo, i, idNodes, P );
- }
- }
-
-
- // Set nodes of the found bottom face in good order
- DUMPSO( " Found bottom face: ");
- i = SortQuadNodes( theMesh, idNodes );
- if ( i ) {
- gp_Pnt Ptmp = P[ i ];
- 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());
- // }
-
- // Gravity center of the top and bottom faces
- gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
- gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
-
- // Get direction from the bottom to the top face
- gp_Vec upDir ( aGCb, aGCt );
- Standard_Real upDirSize = upDir.Magnitude();
- if ( upDirSize <= gp::Resolution() ) return false;
- upDir / upDirSize;
-
- // Assure that the bottom face normal points up
- gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
- Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
- if ( Nb.Dot( upDir ) < 0 ) {
- DUMPSO( "Reverse bottom face");
- swap( 1, 3, idNodes, P );
- }
-
- // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
- Standard_Real minDist = DBL_MAX;
- for ( i = 4; i < 8; i++ ) {
- // projection of P[i] to the plane defined by P[0] and upDir
- gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
- Standard_Real sqDist = P[0].SquareDistance( Pp );
- if ( sqDist < minDist ) {
- minDist = sqDist;
- iMin = i;
- }
- }
- DUMPSO( "Set 4-th");
- swap ( 4, iMin, idNodes, P );
-
- // Set nodes of the top face in good order
- DUMPSO( "Sort top face");
- i = SortQuadNodes( theMesh, &idNodes[4] );
- if ( i ) {
- i += 4;
- gp_Pnt Ptmp = P[ i ];
- P[ i ] = P[ i+1 ];
- P[ i+1 ] = Ptmp;
- }
-
- // Assure that direction of the top face normal is from the bottom face
- gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
- Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
- if ( Nt.Dot( upDir ) < 0 ) {
- DUMPSO( "Reverse top face");
- 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]);
- // }
-
- 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() )
+ SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
+ while ( elemIt->more() )
{
const SMDS_MeshElement* elem = elemIt->next();
if(elem->GetType() == SMDSAbs_0DElement)
{
projector.Perform( point );
if ( projector.IsDone() ) {
- double u, v, minVal = DBL_MAX;
+ double u = 0, v = 0, minVal = DBL_MAX;
for ( int i = projector.NbExt(); i > 0; i-- )
-#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
if ( projector.SquareDistance( i ) < minVal ) {
minVal = projector.SquareDistance( i );
-#else
- if ( projector.Value( i ) < minVal ) {
- minVal = projector.Value( i );
-#endif
projector.Point( i ).Parameter( u, v );
}
result.SetCoord( u, v );
double theTgtAspectRatio,
const bool the2D)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
+ ClearLastCreated();
if ( theTgtAspectRatio < 1.0 )
theTgtAspectRatio = 1.0;
// smooth elements on each TopoDS_Face separately
// ===============================================
- set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
- for ( ; fId != faceIdSet.rend(); ++fId ) {
+ SMESH_MesherHelper helper( *GetMesh() );
+
+ set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treat 0 fId at the end
+ for ( ; fId != faceIdSet.rend(); ++fId )
+ {
// get face surface and submesh
Handle(Geom_Surface) surface;
SMESHDS_SubMesh* faceSubMesh = 0;
TopoDS_Face face;
- double fToler2 = 0, f,l;
+ double fToler2 = 0;
double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
bool isUPeriodic = false, isVPeriodic = false;
- if ( *fId ) {
+ if ( *fId )
+ {
face = TopoDS::Face( aMesh->IndexToShape( *fId ));
surface = BRep_Tool::Surface( face );
faceSubMesh = aMesh->MeshElements( *fId );
fToler2 = BRep_Tool::Tolerance( face );
fToler2 *= fToler2 * 10.;
isUPeriodic = surface->IsUPeriodic();
- if ( isUPeriodic )
- surface->UPeriod();
+ // if ( isUPeriodic )
+ // surface->UPeriod();
isVPeriodic = surface->IsVPeriodic();
- if ( isVPeriodic )
- surface->VPeriod();
+ // if ( isVPeriodic )
+ // surface->VPeriod();
surface->Bounds( u1, u2, v1, v2 );
+ helper.SetSubShape( face );
}
// ---------------------------------------------------------
// for elements on a face, find movable and fixed nodes and
int nbElemOnFace = 0;
itElem = theElems.begin();
// loop on not yet smoothed elements: look for elems on a face
- while ( itElem != theElems.end() ) {
+ while ( itElem != theElems.end() )
+ {
if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
break; // all elements found
{
// 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(SMDSAbs_Face);
bool all = true;
if ( faceSubMesh ) {
+ SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
while ( eIt->more() && all ) {
const SMDS_MeshElement* e = eIt->next();
all = faceSubMesh->Contains( e );
// get nodes to check UV
list< const SMDS_MeshNode* > uvCheckNodes;
+ const SMDS_MeshNode* nodeInFace = 0;
itN = elem->nodesIterator();
nn = 0; nbn = elem->NbNodes();
if(elem->IsQuadratic())
nbn = nbn/2;
while ( nn++ < nbn ) {
node = static_cast<const SMDS_MeshNode*>( itN->next() );
+ if ( node->GetPosition()->GetDim() == 2 )
+ nodeInFace = node;
if ( uvMap.find( node ) == uvMap.end() )
uvCheckNodes.push_back( node );
// add nodes of elems sharing node
const SMDS_PositionPtr& pos = node->GetPosition();
posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
// get existing UV
- switch ( posType ) {
- case SMDS_TOP_FACE: {
- SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
- uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
- break;
- }
- case SMDS_TOP_EDGE: {
- 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 )->GetUParameter();
- uv = pcurve->Value( u ).XY();
- }
- break;
- }
- case SMDS_TOP_VERTEX: {
- TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
- if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
- uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
- break;
- }
- default:;
- }
- // check existing UV
- bool project = true;
- gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
- double dist1 = DBL_MAX, dist2 = 0;
- if ( posType != SMDS_TOP_3DSPACE ) {
- dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
- project = dist1 > fToler2;
- }
+ if ( pos )
+ {
+ bool toCheck = true;
+ uv = helper.GetNodeUV( face, node, nodeInFace, &toCheck );
+ }
+ // compute not existing UV
+ bool project = ( posType == SMDS_TOP_3DSPACE );
+ // double dist1 = DBL_MAX, dist2 = 0;
+ // if ( posType != SMDS_TOP_3DSPACE ) {
+ // dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
+ // project = dist1 > fToler2;
+ // }
if ( project ) { // compute new UV
gp_XY newUV;
+ gp_Pnt pNode = SMESH_NodeXYZ( node );
if ( !getClosestUV( projector, pNode, newUV )) {
MESSAGE("Node Projection Failed " << node);
}
if ( isVPeriodic )
newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
// check new UV
- if ( posType != SMDS_TOP_3DSPACE )
- dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
- if ( dist2 < dist1 )
- uv = newUV;
+ // if ( posType != SMDS_TOP_3DSPACE )
+ // dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
+ // if ( dist2 < dist1 )
+ uv = newUV;
}
}
// store UV in the map
uv2 = pcurve->Value( f );
int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
// assure uv1 < uv2
- if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
- gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
- }
+ if ( uv1.Coord( iPar ) > uv2.Coord( iPar ))
+ std::swap( uv1, uv2 );
// get nodes on seam and its vertices
list< const SMDS_MeshNode* > seamNodes;
SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
setMovableNodes.find( n ) == setMovableNodes.end() )
continue;
// add only nodes being closer to uv2 than to uv1
- gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
- 0.5 * ( n->Y() + nSeam->Y() ),
- 0.5 * ( n->Z() + nSeam->Z() ));
- gp_XY uv;
- getClosestUV( projector, pMid, uv );
- if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
+ // gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
+ // 0.5 * ( n->Y() + nSeam->Y() ),
+ // 0.5 * ( n->Z() + nSeam->Z() ));
+ // gp_XY uv;
+ // getClosestUV( projector, pMid, uv );
+ double x = uvMap[ n ]->Coord( iPar );
+ if ( Abs( uv1.Coord( iPar ) - x ) >
+ Abs( uv2.Coord( iPar ) - x )) {
nodesNearSeam.insert( n );
nbUseMap2++;
}
}
}
if ( maxRatio <= theTgtAspectRatio ) {
- MESSAGE("-- quality achived --");
+ //MESSAGE("-- quality achieved --");
break;
}
if (it+1 == theNbIterations) {
- MESSAGE("-- Iteration limit exceeded --");
+ //MESSAGE("-- Iteration limit exceeded --");
}
} // smoothing iterations
- MESSAGE(" Face id: " << *fId <<
- " Nb iterstions: " << it <<
- " Displacement: " << maxDisplacement <<
- " Aspect Ratio " << maxRatio);
+ // MESSAGE(" Face id: " << *fId <<
+ // " Nb iterstions: " << it <<
+ // " Displacement: " << maxDisplacement <<
+ // " Aspect Ratio " << maxRatio);
// ---------------------------------------
// new nodes positions are computed,
// move medium nodes of quadratic elements
if ( isQuadratic )
{
- SMESH_MesherHelper helper( *GetMesh() );
- if ( !face.IsNull() )
- helper.SetSubShape( face );
+ vector<const SMDS_MeshNode*> nodes;
+ bool checkUV;
list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
- for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
- 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_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
- while ( anIter->more() )
- 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) {
- if ( !surface.IsNull() ) {
- gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[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();
+ for ( ; elemIt != elemsOnFace.end(); ++elemIt )
+ {
+ const SMDS_MeshElement* QF = *elemIt;
+ if ( QF->IsQuadratic() )
+ {
+ nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesIterator() ),
+ SMDS_MeshElement::iterator() );
+ nodes.push_back( nodes[0] );
+ gp_Pnt xyz;
+ for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
+ {
+ if ( !surface.IsNull() )
+ {
+ gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
+ gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
+ gp_XY uv = helper.GetMiddleUV( surface, uv1, uv2 );
+ xyz = surface->Value( uv.X(), uv.Y() );
}
else {
- x = (Ns[i]->X() + Ns[i+2]->X())/2;
- y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
- z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
- }
- if( fabs( Ns[i+1]->X() - x ) > disttol ||
- fabs( Ns[i+1]->Y() - y ) > disttol ||
- fabs( Ns[i+1]->Z() - z ) > disttol ) {
- // we have to move i+1 node
- aMesh->MoveNode( Ns[i+1], x, y, z );
+ xyz = 0.5 * ( SMESH_NodeXYZ( nodes[i-1] ) + SMESH_NodeXYZ( nodes[i+1] ));
}
+ if (( SMESH_NodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
+ // we have to move a medium node
+ aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
}
}
}
}
-//=======================================================================
-//function : isReverse
-//purpose : Return true if normal of prevNodes is not co-directied with
-// gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
-// iNotSame is where prevNodes and nextNodes are different.
-// If result is true then future volume orientation is OK
-//=======================================================================
-
-static bool isReverse(const SMDS_MeshElement* face,
- const vector<const SMDS_MeshNode*>& prevNodes,
- const vector<const SMDS_MeshNode*>& nextNodes,
- const int iNotSame)
+namespace
{
+ //=======================================================================
+ //function : isReverse
+ //purpose : Return true if normal of prevNodes is not co-directied with
+ // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
+ // iNotSame is where prevNodes and nextNodes are different.
+ // If result is true then future volume orientation is OK
+ //=======================================================================
+
+ bool isReverse(const SMDS_MeshElement* face,
+ const vector<const SMDS_MeshNode*>& prevNodes,
+ const vector<const SMDS_MeshNode*>& nextNodes,
+ const int iNotSame)
+ {
+
+ SMESH_NodeXYZ pP = prevNodes[ iNotSame ];
+ SMESH_NodeXYZ pN = nextNodes[ iNotSame ];
+ gp_XYZ extrDir( pN - pP ), faceNorm;
+ SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
+
+ return faceNorm * extrDir < 0.0;
+ }
- SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
- SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
- gp_XYZ extrDir( pN - pP ), faceNorm;
- SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
+ //================================================================================
+ /*!
+ * \brief Assure that theElemSets[0] holds elements, not nodes
+ */
+ //================================================================================
- return faceNorm * extrDir < 0.0;
+ void setElemsFirst( TIDSortedElemSet theElemSets[2] )
+ {
+ if ( !theElemSets[0].empty() &&
+ (*theElemSets[0].begin())->GetType() == SMDSAbs_Node )
+ {
+ std::swap( theElemSets[0], theElemSets[1] );
+ }
+ else if ( !theElemSets[1].empty() &&
+ (*theElemSets[1].begin())->GetType() != SMDSAbs_Node )
+ {
+ std::swap( theElemSets[0], theElemSets[1] );
+ }
+ }
}
//=======================================================================
void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
const vector<TNodeOfNodeListMapItr> & newNodesItVec,
list<const SMDS_MeshElement*>& newElems,
- const int nbSteps,
+ const size_t nbSteps,
SMESH_SequenceOfElemPtr& srcElements)
{
- //MESSAGE("sweepElement " << nbSteps);
SMESHDS_Mesh* aMesh = GetMeshDS();
const int nbNodes = elem->NbNodes();
}
else
{
- const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
+ const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType, nbNodes );
SMDS_MeshCell::applyInterlace( ind, itNN );
SMDS_MeshCell::applyInterlace( ind, prevNod );
SMDS_MeshCell::applyInterlace( ind, nextNod );
}
}
}
+ else if ( elem->GetType() == SMDSAbs_Edge )
+ {
+ // orient a new face same as adjacent one
+ int i1, i2;
+ const SMDS_MeshElement* e;
+ TIDSortedElemSet dummy;
+ if (( e = SMESH_MeshAlgos::FindFaceInSet( nextNod[0], prevNod[0], dummy,dummy, &i1, &i2 )) ||
+ ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[1], nextNod[1], dummy,dummy, &i1, &i2 )) ||
+ ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[0], prevNod[1], dummy,dummy, &i1, &i2 )))
+ {
+ // there is an adjacent face, check order of nodes in it
+ bool sameOrder = ( Abs( i2 - i1 ) == 1 ) ? ( i2 > i1 ) : ( i2 < i1 );
+ if ( sameOrder )
+ {
+ std::swap( itNN[0], itNN[1] );
+ std::swap( prevNod[0], prevNod[1] );
+ std::swap( nextNod[0], nextNod[1] );
+ std::swap( isSingleNode[0], isSingleNode[1] );
+ if ( nbSame > 0 )
+ sames[0] = 1 - sames[0];
+ iNotSameNode = 1 - iNotSameNode;
+ }
+ }
+ }
int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
if ( nbSame > 0 ) {
iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
}
+ if ( baseType == SMDSEntity_Polygon )
+ {
+ if ( nbNodes == 3 ) baseType = SMDSEntity_Triangle;
+ else if ( nbNodes == 4 ) baseType = SMDSEntity_Quadrangle;
+ }
+ else if ( baseType == SMDSEntity_Quad_Polygon )
+ {
+ if ( nbNodes == 6 ) baseType = SMDSEntity_Quad_Triangle;
+ else if ( nbNodes == 8 ) baseType = SMDSEntity_Quad_Quadrangle;
+ }
+
// make new elements
- for (int iStep = 0; iStep < nbSteps; iStep++ )
+ for ( size_t iStep = 0; iStep < nbSteps; iStep++ )
{
// get next nodes
for ( iNode = 0; iNode < nbNodes; iNode++ )
break;
}
case SMDSEntity_Triangle: // TRIANGLE --->
- {
- if ( nbDouble > 0 ) break;
- if ( nbSame == 0 ) // ---> pentahedron
- aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
- nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
-
- else if ( nbSame == 1 ) // ---> pyramid
- aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
- nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
- nextNod[ iSameNode ]);
-
- else // 2 same nodes: ---> tetrahedron
- aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
- nextNod[ iNotSameNode ]);
- break;
- }
+ {
+ if ( nbDouble > 0 ) break;
+ if ( nbSame == 0 ) // ---> pentahedron
+ aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
+ nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
+
+ else if ( nbSame == 1 ) // ---> pyramid
+ aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
+ nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
+ nextNod[ iSameNode ]);
+
+ else // 2 same nodes: ---> tetrahedron
+ aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
+ nextNod[ iNotSameNode ]);
+ break;
+ }
case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
+ {
+ if ( nbSame == 2 )
+ return;
+ if ( nbDouble+nbSame == 2 )
{
- if ( nbSame == 2 )
- return;
- if ( nbDouble+nbSame == 2 )
- {
- if(nbSame==0) { // ---> quadratic quadrangle
- aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
- prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
- }
- else { //(nbSame==1) // ---> quadratic triangle
- 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]);
- else // sames[0]==1
- aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
- midlNod[0], nextNod[2], prevNod[2]);
- }
+ if(nbSame==0) { // ---> quadratic quadrangle
+ aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
+ prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
}
- else if ( nbDouble == 3 )
- {
- if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle
- aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
- prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
+ else { //(nbSame==1) // ---> quadratic triangle
+ if(sames[0]==2) {
+ return; // medium node on axis
}
+ else if(sames[0]==0)
+ aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1],
+ prevNod[2], midlNod[1], nextNod[2] );
+ else // sames[0]==1
+ aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0],
+ prevNod[2], nextNod[2], midlNod[0]);
+ }
+ }
+ else if ( nbDouble == 3 )
+ {
+ if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle
+ aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
+ prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
}
- else
- return;
- break;
}
+ else
+ return;
+ break;
+ }
case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
if ( nbDouble > 0 ) break;
}
break;
}
- case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
+ case SMDSEntity_Quad_Triangle: // sweep (Bi)Quadratic TRIANGLE --->
+ case SMDSEntity_BiQuad_Triangle: /* ??? */ {
if ( nbDouble+nbSame != 3 ) break;
if(nbSame==0) {
// ---> pentahedron with 15 nodes
else if(nbSame==1) {
// ---> pyramid + pentahedron - can not be created since it is needed
// additional middle node at the center of face
- INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
+ //INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
return;
}
else if( nbSame == 2 ) {
default:
break;
- }
- }
+ } // switch ( baseType )
+ } // scope
if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
{
if ( baseType != SMDSEntity_Polygon )
{
- const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
+ const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType,nbNodes);
SMDS_MeshCell::applyInterlace( ind, prevNod );
SMDS_MeshCell::applyInterlace( ind, nextNod );
SMDS_MeshCell::applyInterlace( ind, midlNod );
quantities.push_back( nbNodes );
// side faces
- for (int iface = 0; iface < nbNodes; iface++)
+ // 3--6--2
+ // | |
+ // 7 5
+ // | |
+ // 0--4--1
+ const int iQuad = elem->IsQuadratic();
+ for (int iface = 0; iface < nbNodes; iface += 1+iQuad )
{
- const int prevNbNodes = polyedre_nodes.size();
- int inextface = (iface+1) % nbNodes;
- polyedre_nodes.push_back( prevNod[inextface] );
- polyedre_nodes.push_back( prevNod[iface] );
- if ( prevNod[iface] != nextNod[iface] )
+ const int prevNbNodes = polyedre_nodes.size(); // to detect degenerated face
+ int inextface = (iface+1+iQuad) % nbNodes;
+ int imid = (iface+1) % nbNodes;
+ polyedre_nodes.push_back( prevNod[inextface] ); // 0
+ if ( iQuad ) polyedre_nodes.push_back( prevNod[imid] ); // 4
+ polyedre_nodes.push_back( prevNod[iface] ); // 1
+ if ( prevNod[iface] != nextNod[iface] ) // 1 != 2
{
- if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
- polyedre_nodes.push_back( nextNod[iface] );
+ if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); // 5
+ polyedre_nodes.push_back( nextNod[iface] ); // 2
}
- if ( prevNod[inextface] != nextNod[inextface] )
+ if ( iQuad ) polyedre_nodes.push_back( nextNod[imid] ); // 6
+ if ( prevNod[inextface] != nextNod[inextface] ) // 0 != 3
{
- polyedre_nodes.push_back( nextNod[inextface] );
- if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
+ polyedre_nodes.push_back( nextNod[inextface] ); // 3
+ if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);// 7
}
const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
if ( nbFaceNodes > 2 )
polyedre_nodes.resize( prevNbNodes );
}
aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
- }
+
+ } // try to create a polyherdal prism
if ( aNewElem ) {
newElems.push_back( aNewElem );
- myLastCreatedElems.Append(aNewElem);
- srcElements.Append( elem );
+ myLastCreatedElems.push_back(aNewElem);
+ srcElements.push_back( elem );
}
// set new prev nodes
for ( iNode = 0; iNode < nbNodes; iNode++ )
prevNod[ iNode ] = nextNod[ iNode ];
- } // for steps
+ } // loop on steps
}
//=======================================================================
//=======================================================================
void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
- TElemOfElemListMap & newElemsMap,
+ TTElemOfElemListMap & newElemsMap,
TElemOfVecOfNnlmiMap & elemNewNodesMap,
TIDSortedElemSet& elemSet,
const int nbSteps,
ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
SMESHDS_Mesh* aMesh = GetMeshDS();
- // Find nodes belonging to only one initial element - sweep them to get edges.
+ // Find nodes belonging to only one initial element - sweep them into edges.
TNodeOfNodeListMapItr nList = mapNewNodes.begin();
for ( ; nList != mapNewNodes.end(); nList++ )
const SMDS_MeshElement* el = 0;
SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
while ( eIt->more() && nbInitElems < 2 ) {
- el = eIt->next();
- SMDSAbs_ElementType type = el->GetType();
- if ( type == SMDSAbs_Volume || type < highType ) continue;
+ const SMDS_MeshElement* e = eIt->next();
+ SMDSAbs_ElementType type = e->GetType();
+ if ( type == SMDSAbs_Volume ||
+ type < highType ||
+ !elemSet.count(e))
+ continue;
if ( type > highType ) {
nbInitElems = 0;
- highType = type;
+ highType = type;
}
- nbInitElems += elemSet.count(el);
+ el = e;
+ ++nbInitElems;
}
- if ( nbInitElems < 2 ) {
+ if ( nbInitElems == 1 ) {
bool NotCreateEdge = el && el->IsMediumNode(node);
if(!NotCreateEdge) {
vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
// Make a ceiling for each element ie an equal element of last new nodes.
// Find free links of faces - make edges and sweep them into faces.
- TElemOfElemListMap::iterator itElem = newElemsMap.begin();
+ ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace;
+
+ TTElemOfElemListMap::iterator itElem = newElemsMap.begin();
TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
{
if ( !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( elem );
+ myLastCreatedElems.push_back(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back()));
+ srcElements.push_back( elem );
}
}
else {
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( elem );
+ myLastCreatedElems.push_back(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back(),
+ vecNewNodes[ 2 ]->second.back()));
+ srcElements.push_back( elem );
}
}
}
const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
// check if a link n1-n2 is free
- if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
+ if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
hasFreeLinks = true;
// make a new edge and a ceiling for a new edge
const SMDS_MeshElement* edge;
if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
- myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
- srcElements.Append( myLastCreatedElems.Last() );
+ myLastCreatedElems.push_back( edge = aMesh->AddEdge( n1, n2 )); // free link edge
+ srcElements.push_back( myLastCreatedElems.back() );
}
n1 = vecNewNodes[ iNode ]->second.back();
n2 = vecNewNodes[ iNext ]->second.back();
if ( !aMesh->FindEdge( n1, n2 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
- srcElements.Append( edge );
+ myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2 )); // new edge ceiling
+ srcElements.push_back( edge );
}
}
}
const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
// check if a link is free
- if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
- ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
- ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
+ if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
+ ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
+ ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
hasFreeLinks = true;
// make an edge and a ceiling for a new edge
// find medium node
if ( !aMesh->FindEdge( n1, n2, n3 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
- srcElements.Append( elem );
+ myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2, n3 )); // free link edge
+ srcElements.push_back( elem );
}
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 )); // ceiling edge
- srcElements.Append( elem );
+ myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
+ srcElements.push_back( elem );
}
}
}
// sweep free links into faces
- if ( hasFreeLinks ) {
+ if ( hasFreeLinks ) {
list<const SMDS_MeshElement*> & newVolumes = itElem->second;
int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
+ set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
for ( iNode = 0; iNode < nbNodes; iNode++ ) {
initNodeSet.insert( vecNewNodes[ iNode ]->first );
topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
}
+ if ( isQuadratic && nbNodes % 2 ) { // node set for the case of a biquadratic
+ initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
+ initNodeSetNoCenter.erase( vecNewNodes.back()->first );
+ }
for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
std::advance( v, volNb );
SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
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
+ if ( vTool.IsFreeFace( iF ) &&
+ vTool.GetFaceNodes( iF, faceNodeSet ) &&
+ initNodeSet != faceNodeSet) // except an initial face
{
if ( nbSteps == 1 && faceNodeSet == topNodeSet )
continue;
+ if ( faceNodeSet == initNodeSetNoCenter )
+ 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() )
+ vector<const SMDS_MeshNode*>::iterator lastCommom;
+ commonNodes.resize( nbNodes, 0 );
+ lastCommom = std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
+ initNodeSet.begin(), initNodeSet.end(),
+ commonNodes.begin());
+ if ( std::distance( commonNodes.begin(), lastCommom ) == 3 )
srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
else
srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
if ( freeInd.empty() )
continue;
- // create faces for all steps;
+ // create wall 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++ ) {
+ for ( int iStep = 0; iStep < nbSteps; iStep++ )
+ {
vTool.Set( *v, /*ignoreCentralNodes=*/false );
vTool.SetExternalNormal();
const int nextShift = vTool.IsForward() ? +1 : -1;
if ( f )
aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
else
- myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
- newOrder[ 2 ] ));
+ myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
+ newOrder[ 2 ] ));
}
}
else if ( nbn == 4 ) ///// quadrangle
if ( f )
aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
else
- myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
- newOrder[ 2 ], newOrder[ 3 ]));
+ myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
+ newOrder[ 2 ], newOrder[ 3 ]));
}
}
else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
if ( f )
aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
else
- myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
- newOrder[ 1 ],
- newOrder[ 2 ],
- newOrder[ 3 ],
- newOrder[ 4 ],
- newOrder[ 5 ] ));
+ myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ],
+ newOrder[ 1 ],
+ newOrder[ 2 ],
+ newOrder[ 3 ],
+ newOrder[ 4 ],
+ newOrder[ 5 ] ));
}
}
else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
if ( f )
aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
else
- myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
- newOrder[ 2 ], newOrder[ 3 ],
- newOrder[ 4 ], newOrder[ 5 ],
- newOrder[ 6 ], newOrder[ 7 ]));
+ myLastCreatedElems.push_back(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
+ newOrder[ 2 ], newOrder[ 3 ],
+ newOrder[ 4 ], newOrder[ 5 ],
+ newOrder[ 6 ], newOrder[ 7 ]));
}
}
else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
if ( f )
aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
else
- myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
- newOrder[ 2 ], newOrder[ 3 ],
- newOrder[ 4 ], newOrder[ 5 ],
- newOrder[ 6 ], newOrder[ 7 ],
- newOrder[ 8 ]));
+ myLastCreatedElems.push_back(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
+ newOrder[ 2 ], newOrder[ 3 ],
+ newOrder[ 4 ], newOrder[ 5 ],
+ newOrder[ 6 ], newOrder[ 7 ],
+ newOrder[ 8 ]));
}
}
else //////// polygon
if ( f )
aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
else
- AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
+ AddElement( polygon_nodes, polyFace.SetQuad( (*v)->IsQuadratic() ));
}
}
- while ( srcElements.Length() < myLastCreatedElems.Length() )
- srcElements.Append( *srcEdge );
+ while ( srcElements.size() < myLastCreatedElems.size() )
+ srcElements.push_back( *srcEdge );
} // loop on free faces
// Make a ceiling face with a normal external to a volume
+ // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
-
int iF = lastVol.GetFaceIndex( aFaceLastNodes );
- if ( iF >= 0 ) {
+
+ if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
+ aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
+ iF = lastVol.GetFaceIndex( aFaceLastNodes );
+ }
+ if ( iF >= 0 )
+ {
lastVol.SetExternalNormal();
const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
- int nbn = lastVol.NbFaceNodes( iF );
- if ( nbn == 3 ) {
- if (!hasFreeLinks ||
- !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
- }
- else if ( nbn == 4 )
- {
- if (!hasFreeLinks ||
- !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
- }
- else if ( nbn == 6 && isQuadratic )
+ const int nbn = lastVol.NbFaceNodes( iF );
+ vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
+ if ( !hasFreeLinks ||
+ !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
{
- 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 if ( nbn == 8 && isQuadratic )
- {
- 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]));
- }
- else if ( nbn == 9 && isQuadratic )
- {
- if (!hasFreeLinks ||
- !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
- SMDSAbs_Face, /*noMedium=*/false) )
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7],
- nodes[8]));
- }
- else {
- vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
- if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
- myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
- }
+ const vector<int>& interlace =
+ SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn );
+ SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec );
+
+ AddElement( nodeVec, anyFace.Init( elem ));
- while ( srcElements.Length() < myLastCreatedElems.Length() )
- srcElements.Append( elem );
+ while ( srcElements.size() < myLastCreatedElems.size() )
+ srcElements.push_back( elem );
+ }
}
} // loop on swept elements
}
//=======================================================================
SMESH_MeshEditor::PGroupIDs
-SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
+SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2],
const gp_Ax1& theAxis,
const double theAngle,
const int theNbSteps,
const bool theMakeGroups,
const bool theMakeWalls)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
+
+ setElemsFirst( theElemSets );
+ myLastCreatedElems.reserve( theElemSets[0].size() * theNbSteps );
+ myLastCreatedNodes.reserve( theElemSets[1].size() * theNbSteps );
// source elements for each generated one
SMESH_SequenceOfElemPtr srcElems, srcNodes;
+ srcElems.reserve( theElemSets[0].size() );
+ srcNodes.reserve( theElemSets[1].size() );
- MESSAGE( "RotationSweep()");
gp_Trsf aTrsf;
aTrsf.SetRotation( theAxis, theAngle );
gp_Trsf aTrsf2;
TNodeOfNodeListMap mapNewNodes;
TElemOfVecOfNnlmiMap mapElemNewNodes;
- TElemOfElemListMap newElemsMap;
+ TTElemOfElemListMap newElemsMap;
const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
myMesh->NbFaces(ORDER_QUADRATIC) +
myMesh->NbVolumes(ORDER_QUADRATIC) );
- // loop on theElems
+ // loop on theElemSets
TIDSortedElemSet::iterator itElem;
- for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- const SMDS_MeshElement* elem = *itElem;
- if ( !elem || elem->GetType() == SMDSAbs_Volume )
- continue;
- vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
- newNodesItVec.reserve( elem->NbNodes() );
+ for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+ {
+ TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ 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 = cast2Node( itN->next() );
+ // loop on elem nodes
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
+ {
+ 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 );
+ 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.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
- list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
- if ( listNewNodes.empty() )
- {
- // check if we are to create medium nodes between corner ones
- bool needMediumNodes = false;
- if ( isQuadraticMesh )
+ // check if a node has been already sweeped
+ TNodeOfNodeListMapItr nIt =
+ mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+ list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+ if ( listNewNodes.empty() )
{
- SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
- while (it->more() && !needMediumNodes )
+ // check if we are to create medium nodes between corner ones
+ bool needMediumNodes = false;
+ if ( isQuadraticMesh )
{
- const SMDS_MeshElement* invElem = it->next();
- if ( invElem != elem && !theElems.count( invElem )) continue;
- needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
- if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
- needMediumNodes = true;
+ SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
+ while (it->more() && !needMediumNodes )
+ {
+ const SMDS_MeshElement* invElem = it->next();
+ if ( invElem != elem && !theElems.count( invElem )) continue;
+ needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
+ if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+ needMediumNodes = true;
+ }
}
- }
- // make new nodes
- const SMDS_MeshNode * newNode = node;
- for ( int i = 0; i < theNbSteps; i++ ) {
- if ( !isOnAxis ) {
- if ( needMediumNodes ) // create a medium node
- {
- aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ // make new nodes
+ const SMDS_MeshNode * newNode = node;
+ for ( int i = 0; i < theNbSteps; i++ ) {
+ if ( !isOnAxis ) {
+ if ( needMediumNodes ) // create a medium node
+ {
+ aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ myLastCreatedNodes.push_back(newNode);
+ srcNodes.push_back( node );
+ listNewNodes.push_back( newNode );
+ aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ }
+ else {
+ aTrsf.Transforms( coord[0], coord[1], coord[2] );
+ }
+ // create a corner node
newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
- myLastCreatedNodes.Append(newNode);
- srcNodes.Append( node );
+ myLastCreatedNodes.push_back(newNode);
+ srcNodes.push_back( node );
listNewNodes.push_back( newNode );
- aTrsf2.Transforms( coord[0], coord[1], coord[2] );
}
else {
- aTrsf.Transforms( coord[0], coord[1], coord[2] );
+ listNewNodes.push_back( newNode );
+ // if ( needMediumNodes )
+ // listNewNodes.push_back( newNode );
}
- // create a corner node
- 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 ( needMediumNodes )
- // listNewNodes.push_back( newNode );
}
}
+ newNodesItVec.push_back( nIt );
}
- newNodesItVec.push_back( nIt );
+ // make new elements
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
}
- // make new elements
- sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
}
if ( theMakeWalls )
- makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], theNbSteps, srcElems );
PGroupIDs newGroupIDs;
if ( theMakeGroups )
return newGroupIDs;
}
-
//=======================================================================
-//function : CreateNode
-//purpose :
+//function : ExtrusParam
+//purpose : standard construction
//=======================================================================
-const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
- const double y,
- const double z,
- const double tolnode,
- SMESH_SequenceOfNode& aNodes)
+
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec& theStep,
+ const int theNbSteps,
+ const std::list<double>& theScales,
+ const std::list<double>& theAngles,
+ const gp_XYZ* theBasePoint,
+ const int theFlags,
+ const double theTolerance):
+ myDir( theStep ),
+ myBaseP( Precision::Infinite(), 0, 0 ),
+ myFlags( theFlags ),
+ myTolerance( theTolerance ),
+ myElemsToUse( NULL )
{
- // myLastCreatedElems.Clear();
- // myLastCreatedNodes.Clear();
+ mySteps = new TColStd_HSequenceOfReal;
+ const double stepSize = theStep.Magnitude();
+ for (int i=1; i<=theNbSteps; i++ )
+ mySteps->Append( stepSize );
- gp_Pnt P1(x,y,z);
- SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
+ if ( !theScales.empty() )
+ {
+ if ( IsScaleVariation() && (int)theScales.size() < theNbSteps )
+ linearScaleVariation( theNbSteps, const_cast< std::list<double>& >( theScales ));
- // try to search in sequence of existing nodes
- // if aNodes.Length()>0 we 'nave to use given sequence
- // else - use all nodes of mesh
- if(aNodes.Length()>0) {
- int i;
- for(i=1; i<=aNodes.Length(); i++) {
- gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
- if(P1.Distance(P2)<tolnode)
- return aNodes.Value(i);
+ // add medium scales
+ std::list<double>::const_iterator s2 = theScales.begin(), s1 = s2++;
+ myScales.reserve( theNbSteps * 2 );
+ myScales.push_back( 0.5 * ( *s1 + 1. ));
+ myScales.push_back( *s1 );
+ for ( ; s2 != theScales.end(); s1 = s2++ )
+ {
+ myScales.push_back( 0.5 * ( *s1 + *s2 ));
+ myScales.push_back( *s2 );
}
}
- else {
- SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
- while(itn->more()) {
- const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
- gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
- if(P1.Distance(P2)<tolnode)
- return aN;
+
+ if ( !theAngles.empty() )
+ {
+ std::list<double>& angles = const_cast< std::list<double>& >( theAngles );
+ if ( IsAngleVariation() && (int)theAngles.size() < theNbSteps )
+ linearAngleVariation( theNbSteps, angles );
+
+ // accumulate angles
+ double angle = 0;
+ int nbAngles = 0;
+ std::list<double>::iterator a1 = angles.begin(), a2;
+ for ( ; a1 != angles.end(); ++a1, ++nbAngles )
+ {
+ angle += *a1;
+ *a1 = angle;
+ }
+ while ( nbAngles++ < theNbSteps )
+ angles.push_back( angles.back() );
+
+ // add medium angles
+ a2 = angles.begin(), a1 = a2++;
+ myAngles.push_back( 0.5 * *a1 );
+ myAngles.push_back( *a1 );
+ for ( ; a2 != angles.end(); a1 = a2++ )
+ {
+ myAngles.push_back( 0.5 * ( *a1 + *a2 ));
+ myAngles.push_back( *a2 );
}
}
- // create new node and return it
- const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
- //myLastCreatedNodes.Append(NewNode);
- return NewNode;
-}
+ if ( theBasePoint )
+ {
+ myBaseP = *theBasePoint;
+ }
+ if (( theFlags & EXTRUSION_FLAG_SEW ) &&
+ ( theTolerance > 0 ))
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
+ }
+ else
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
+ }
+}
//=======================================================================
-//function : ExtrusionSweep
-//purpose :
+//function : ExtrusParam
+//purpose : steps are given explicitly
//=======================================================================
-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)
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Dir& theDir,
+ Handle(TColStd_HSequenceOfReal) theSteps,
+ const int theFlags,
+ const double theTolerance):
+ myDir( theDir ),
+ mySteps( theSteps ),
+ myFlags( theFlags ),
+ myTolerance( theTolerance ),
+ myElemsToUse( NULL )
{
- ExtrusParam aParams;
- aParams.myDir = gp_Dir(theStep);
- aParams.myNodes.Clear();
- aParams.mySteps = new TColStd_HSequenceOfReal;
- int i;
- for(i=1; i<=theNbSteps; i++)
- aParams.mySteps->Append(theStep.Magnitude());
-
- return
- ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
+ if (( theFlags & EXTRUSION_FLAG_SEW ) &&
+ ( theTolerance > 0 ))
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
+ }
+ else
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
+ }
}
-
//=======================================================================
-//function : ExtrusionSweep
-//purpose :
+//function : ExtrusParam
+//purpose : for extrusion by normal
//=======================================================================
-SMESH_MeshEditor::PGroupIDs
-SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
- ExtrusParam& theParams,
- TElemOfElemListMap& newElemsMap,
- const bool theMakeGroups,
- const int theFlags,
- const double theTolerance)
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const double theStepSize,
+ const int theNbSteps,
+ const int theFlags,
+ const int theDim ):
+ myDir( 1,0,0 ),
+ mySteps( new TColStd_HSequenceOfReal ),
+ myFlags( theFlags ),
+ myTolerance( 0 ),
+ myElemsToUse( NULL )
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- // source elements for each generated one
- SMESH_SequenceOfElemPtr srcElems, srcNodes;
+ for (int i = 0; i < theNbSteps; i++ )
+ mySteps->Append( theStepSize );
- SMESHDS_Mesh* aMesh = GetMeshDS();
+ if ( theDim == 1 )
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal1D;
+ }
+ else
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal2D;
+ }
+}
- int nbsteps = theParams.mySteps->Length();
+//=======================================================================
+//function : ExtrusParam
+//purpose : for extrusion along path
+//=======================================================================
- TNodeOfNodeListMap mapNewNodes;
- //TNodeOfNodeVecMap mapNewNodes;
- TElemOfVecOfNnlmiMap mapElemNewNodes;
- //TElemOfVecOfMapNodesMap mapElemNewNodes;
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const std::vector< PathPoint >& thePoints,
+ const gp_Pnt* theBasePoint,
+ const std::list<double>& theScales,
+ const bool theMakeGroups )
+ : myBaseP( Precision::Infinite(), 0, 0 ),
+ myFlags( EXTRUSION_FLAG_BOUNDARY | ( theMakeGroups ? EXTRUSION_FLAG_GROUPS : 0 )),
+ myPathPoints( thePoints )
+{
+ if ( theBasePoint )
+ {
+ myBaseP = theBasePoint->XYZ();
+ }
- const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
- myMesh->NbFaces(ORDER_QUADRATIC) +
- myMesh->NbVolumes(ORDER_QUADRATIC) );
- // loop on theElems
- TIDSortedElemSet::iterator itElem;
- for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
- // check element type
- const SMDS_MeshElement* elem = *itElem;
- if ( !elem || elem->GetType() == SMDSAbs_Volume )
- continue;
+ if ( !theScales.empty() )
+ {
+ // add medium scales
+ std::list<double>::const_iterator s2 = theScales.begin(), s1 = s2++;
+ myScales.reserve( thePoints.size() * 2 );
+ myScales.push_back( 0.5 * ( 1. + *s1 ));
+ myScales.push_back( *s1 );
+ for ( ; s2 != theScales.end(); s1 = s2++ )
+ {
+ myScales.push_back( 0.5 * ( *s1 + *s2 ));
+ myScales.push_back( *s2 );
+ }
+ }
- vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
- newNodesItVec.reserve( elem->NbNodes() );
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesAlongTrack;
+}
- // loop on elem nodes
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() )
- {
- // check if a node has been already sweeped
- const SMDS_MeshNode* node = cast2Node( itN->next() );
- TNodeOfNodeListMap::iterator nIt =
- mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
- list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
- if ( listNewNodes.empty() )
- {
- // make new nodes
+//=======================================================================
+//function : ExtrusParam::SetElementsToUse
+//purpose : stores elements to use for extrusion by normal, depending on
+// state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag;
+// define myBaseP for scaling
+//=======================================================================
- // check if we are to create medium nodes between corner ones
- bool needMediumNodes = false;
- if ( isQuadraticMesh )
- {
- SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
- while (it->more() && !needMediumNodes )
- {
- const SMDS_MeshElement* invElem = it->next();
- if ( invElem != elem && !theElems.count( invElem )) continue;
- needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
- if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
- needMediumNodes = true;
- }
- }
+void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems,
+ const TIDSortedElemSet& nodes )
+{
+ myElemsToUse = ToUseInpElemsOnly() ? & elems : 0;
- double coord[] = { node->X(), node->Y(), node->Z() };
- for ( int i = 0; i < nbsteps; i++ )
- {
- if ( needMediumNodes ) // create a medium node
- {
- double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
- double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
- double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
- if( theFlags & EXTRUSION_FLAG_SEW ) {
- const SMDS_MeshNode * newNode = CreateNode(x, y, z,
- theTolerance, theParams.myNodes);
- listNewNodes.push_back( newNode );
- }
- else {
- const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
- myLastCreatedNodes.Append(newNode);
- srcNodes.Append( node );
- listNewNodes.push_back( newNode );
- }
- }
- // create a corner node
- coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
- coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
- coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
- if( theFlags & EXTRUSION_FLAG_SEW ) {
- const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
- theTolerance, theParams.myNodes);
- 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 );
- }
+ if ( Precision::IsInfinite( myBaseP.X() )) // myBaseP not defined
+ {
+ myBaseP.SetCoord( 0.,0.,0. );
+ TIDSortedElemSet newNodes;
+
+ const TIDSortedElemSet* elemSets[] = { &elems, &nodes };
+ for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+ {
+ const TIDSortedElemSet& elements = *( elemSets[ is2ndSet ]);
+ TIDSortedElemSet::const_iterator itElem = elements.begin();
+ for ( ; itElem != elements.end(); itElem++ )
+ {
+ const SMDS_MeshElement* elem = *itElem;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+ const SMDS_MeshElement* node = itN->next();
+ if ( newNodes.insert( node ).second )
+ myBaseP += SMESH_NodeXYZ( node );
}
}
- newNodesItVec.push_back( nIt );
}
- // make new elements
- sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
+ myBaseP /= newNodes.size();
}
+}
- if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
- makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
- }
- PGroupIDs newGroupIDs;
- if ( theMakeGroups )
- newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
+//=======================================================================
+//function : ExtrusParam::beginStepIter
+//purpose : prepare iteration on steps
+//=======================================================================
- return newGroupIDs;
+void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes )
+{
+ myWithMediumNodes = withMediumNodes;
+ myNextStep = 1;
+ myCurSteps.clear();
}
+//=======================================================================
+//function : ExtrusParam::moreSteps
+//purpose : are there more steps?
+//=======================================================================
+bool SMESH_MeshEditor::ExtrusParam::moreSteps()
+{
+ return myNextStep <= mySteps->Length() || !myCurSteps.empty();
+}
//=======================================================================
-//function : ExtrusionAlongTrack
-//purpose :
+//function : ExtrusParam::nextStep
+//purpose : returns the next step
//=======================================================================
-SMESH_MeshEditor::Extrusion_Error
-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)
+
+double SMESH_MeshEditor::ExtrusParam::nextStep()
{
- MESSAGE("ExtrusionAlongTrack");
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ double res = 0;
+ if ( !myCurSteps.empty() )
+ {
+ res = myCurSteps.back();
+ myCurSteps.pop_back();
+ }
+ else if ( myNextStep <= mySteps->Length() )
+ {
+ myCurSteps.push_back( mySteps->Value( myNextStep ));
+ ++myNextStep;
+ if ( myWithMediumNodes )
+ {
+ myCurSteps.back() /= 2.;
+ myCurSteps.push_back( myCurSteps.back() );
+ }
+ res = nextStep();
+ }
+ return res;
+}
- int aNbE;
- std::list<double> aPrms;
- TIDSortedElemSet::iterator itElem;
+//=======================================================================
+//function : ExtrusParam::makeNodesByDir
+//purpose : create nodes for standard extrusion
+//=======================================================================
- gp_XYZ aGC;
- TopoDS_Edge aTrackEdge;
- TopoDS_Vertex aV1, aV2;
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByDir( SMESHDS_Mesh* mesh,
+ const SMDS_MeshNode* srcNode,
+ std::list<const SMDS_MeshNode*> & newNodes,
+ const bool makeMediumNodes)
+{
+ gp_XYZ p = SMESH_NodeXYZ( srcNode );
- SMDS_ElemIteratorPtr aItE;
- SMDS_NodeIteratorPtr aItN;
- SMDSAbs_ElementType aTypeE;
+ int nbNodes = 0;
+ for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
+ {
+ p += myDir.XYZ() * nextStep();
+ const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
+ newNodes.push_back( newNode );
+ }
- TNodeOfNodeListMap mapNewNodes;
+ if ( !myScales.empty() || !myAngles.empty() )
+ {
+ gp_XYZ center = myBaseP;
+ gp_Ax1 ratationAxis( center, myDir );
+ gp_Trsf rotation;
- // 1. Check data
- aNbE = theElements.size();
- // nothing to do
- if ( !aNbE )
- return EXTR_NO_ELEMENTS;
+ std::list<const SMDS_MeshNode*>::iterator nIt = newNodes.begin();
+ size_t i = !makeMediumNodes;
+ for ( beginStepIter( makeMediumNodes );
+ moreSteps();
+ ++nIt, i += 1 + !makeMediumNodes )
+ {
+ center += myDir.XYZ() * nextStep();
- // 1.1 Track Pattern
- ASSERT( theTrack );
-
- SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
-
- aItE = pSubMeshDS->GetElements();
- 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->GetSubShape();
- // 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;
+ gp_XYZ xyz = SMESH_NodeXYZ( *nIt );
+ bool moved = false;
+ if ( i < myScales.size() )
+ {
+ xyz = ( myScales[i] * ( xyz - center )) + center;
+ moved = true;
+ }
+ if ( !myAngles.empty() )
+ {
+ rotation.SetRotation( ratationAxis, myAngles[i] );
+ rotation.Transforms( xyz );
+ moved = true;
}
+ if ( moved )
+ mesh->MoveNode( *nIt, xyz.X(), xyz.Y(), xyz.Z() );
+ else
+ 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;
}
-
- return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
- theHasRefPoint, theRefPoint, theMakeGroups);
+ return nbNodes;
}
-
//=======================================================================
-//function : ExtrusionAlongTrack
-//purpose :
+//function : ExtrusParam::makeNodesByDirAndSew
+//purpose : create nodes for standard extrusion with sewing
//=======================================================================
-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();
-
- int aNbE;
- std::list<double> aPrms;
- TIDSortedElemSet::iterator itElem;
- gp_XYZ aGC;
- TopoDS_Edge aTrackEdge;
- TopoDS_Vertex aV1, aV2;
-
- SMDS_ElemIteratorPtr aItE;
- SMDS_NodeIteratorPtr aItN;
- SMDSAbs_ElementType aTypeE;
-
- TNodeOfNodeListMap mapNewNodes;
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByDirAndSew( SMESHDS_Mesh* mesh,
+ const SMDS_MeshNode* srcNode,
+ std::list<const SMDS_MeshNode*> & newNodes,
+ const bool makeMediumNodes)
+{
+ gp_XYZ P1 = SMESH_NodeXYZ( srcNode );
- // 1. Check data
- aNbE = theElements.size();
- // nothing to do
- if ( !aNbE )
- return EXTR_NO_ELEMENTS;
+ int nbNodes = 0;
+ for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
+ {
+ P1 += myDir.XYZ() * nextStep();
- // 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();
-
- if( aS == SMESH_Mesh::PseudoShape() ) {
- //Mesh without shape
- const SMDS_MeshNode* currentNode = NULL;
- const SMDS_MeshNode* prevNode = theN1;
- std::vector<const SMDS_MeshNode*> aNodesList;
- aNodesList.push_back(theN1);
- int nbEdges = 0, conn=0;
- const SMDS_MeshElement* prevElem = NULL;
- const SMDS_MeshElement* currentElem = NULL;
- int totalNbEdges = theTrack->NbEdges();
- SMDS_ElemIteratorPtr nIt;
-
- //check start node
- if( !theTrack->GetMeshDS()->Contains(theN1) ) {
- return EXTR_BAD_STARTING_NODE;
- }
-
- conn = nbEdgeConnectivity(theN1);
- if(conn > 2)
- return EXTR_PATH_NOT_EDGE;
-
- aItE = theN1->GetInverseElementIterator();
- prevElem = aItE->next();
- currentElem = prevElem;
- //Get all nodes
- if(totalNbEdges == 1 ) {
- nIt = currentElem->nodesIterator();
- currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
- if(currentNode == prevNode)
- currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
- aNodesList.push_back(currentNode);
- } else {
- nIt = currentElem->nodesIterator();
- while( nIt->more() ) {
- currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
- if(currentNode == prevNode)
- currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
- aNodesList.push_back(currentNode);
-
- //case of the closed mesh
- if(currentNode == theN1) {
- nbEdges++;
+ // try to search in sequence of existing nodes
+ // if myNodes.size()>0 we 'nave to use given sequence
+ // else - use all nodes of mesh
+ const SMDS_MeshNode * node = 0;
+ if ( myNodes.Length() > 0 )
+ {
+ for ( int i = 1; i <= myNodes.Length(); i++ )
+ {
+ SMESH_NodeXYZ P2 = myNodes.Value(i);
+ if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
+ {
+ node = myNodes.Value(i);
break;
}
-
- conn = nbEdgeConnectivity(currentNode);
- if(conn > 2) {
- return EXTR_PATH_NOT_EDGE;
- }else if( conn == 1 && nbEdges > 0 ) {
- //End of the path
- nbEdges++;
+ }
+ }
+ else
+ {
+ SMDS_NodeIteratorPtr itn = mesh->nodesIterator();
+ while(itn->more())
+ {
+ SMESH_NodeXYZ P2 = itn->next();
+ if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
+ {
+ node = P2._node;
break;
- }else {
- prevNode = currentNode;
- aItE = currentNode->GetInverseElementIterator();
- currentElem = aItE->next();
- if( currentElem == prevElem)
- currentElem = aItE->next();
- nIt = currentElem->nodesIterator();
- prevElem = currentElem;
- nbEdges++;
- }
- }
- }
-
- if(nbEdges != totalNbEdges)
- return EXTR_PATH_NOT_EDGE;
-
- TopTools_SequenceOfShape Edges;
- double x1,x2,y1,y2,z1,z2;
- list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
- int startNid = theN1->GetID();
- for(int i = 1; i < aNodesList.size(); i++) {
- x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
- y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
- z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
- TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
- list<SMESH_MeshEditor_PathPoint> LPP;
- aPrms.clear();
- MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
- LLPPs.push_back(LPP);
- if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
- else startNid = aNodesList[i-1]->GetID();
-
- }
-
- 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();
- SMESH_MeshEditor_PathPoint PP2;
- fullList.pop_back();
- itLLPP++;
- for(; itLLPP!=LLPPs.end(); itLLPP++) {
- list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
- itPP = currList.begin();
- 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!=currList.end(); itPP++) {
- fullList.push_back( *itPP );
- }
- PP1 = fullList.back();
- fullList.pop_back();
- }
- fullList.push_back(PP1);
-
- } // Sub-shape for the Pattern must be an Edge or Wire
- else 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 );
- const SMDS_MeshNode* aN1 = 0;
- const SMDS_MeshNode* aN2 = 0;
- if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
- aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
- aN1 = aItN->next();
- }
- if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
- aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
- 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;
- TopoDS_Vertex aVprev;
- 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 );
- bool aN1isOK = false, aN2isOK = false;
- if ( aVprev.IsNull() ) {
- // if previous vertex is not yet defined, it means that we in the beginning of wire
- // and we have to find initial vertex corresponding to starting node theN1
- const SMDS_MeshNode* aN1 = 0;
- const SMDS_MeshNode* aN2 = 0;
-
- if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
- aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
- aN1 = aItN->next();
- }
- if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
- aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
- aN2 = aItN->next();
- }
- // starting node must be aN1 or aN2
- aN1isOK = ( aN1 && aN1 == theN1 );
- aN2isOK = ( aN2 && aN2 == theN1 );
}
- else {
- // we have specified ending vertex of the previous edge on the previous iteration
- // and we have just to check that it corresponds to any vertex in current segment
- aN1isOK = aVprev.IsSame( aV1 );
- aN2isOK = aVprev.IsSame( aV2 );
- }
- if ( !aN1isOK && !aN2isOK ) 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, aN1isOK, LPP);
- LLPPs.push_back(LPP);
- UsedNums.Add(k);
- // update startN for search following egde
- if ( aN1isOK ) aVprev = aV2;
- else aVprev = aV1;
- 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( ( D1.XYZ() + D2.XYZ() ) / 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;
- }
- return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
- theHasRefPoint, theRefPoint, theMakeGroups);
-}
+ if ( !node )
+ node = mesh->AddNode( P1.X(), P1.Y(), P1.Z() );
+
+ newNodes.push_back( node );
+
+ } // loop on steps
+ return nbNodes;
+}
//=======================================================================
-//function : MakeEdgePathPoints
-//purpose : auxilary for ExtrusionAlongTrack
+//function : ExtrusParam::makeNodesByNormal2D
+//purpose : create nodes for extrusion using normals of faces
//=======================================================================
-SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
- const TopoDS_Edge& aTrackEdge,
- bool FirstIsStart,
- list<SMESH_MeshEditor_PathPoint>& LPP)
+
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByNormal2D( SMESHDS_Mesh* mesh,
+ const SMDS_MeshNode* srcNode,
+ std::list<const SMDS_MeshNode*> & newNodes,
+ const bool makeMediumNodes)
{
- 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( FirstIsStart ) {
- if ( aT1 > aT2 ) {
- aPrms.reverse();
+ const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL );
+
+ gp_XYZ p = SMESH_NodeXYZ( srcNode );
+
+ // get normals to faces sharing srcNode
+ vector< gp_XYZ > norms, baryCenters;
+ gp_XYZ norm, avgNorm( 0,0,0 );
+ SMDS_ElemIteratorPtr faceIt = srcNode->GetInverseElementIterator( SMDSAbs_Face );
+ while ( faceIt->more() )
+ {
+ const SMDS_MeshElement* face = faceIt->next();
+ if ( myElemsToUse && !myElemsToUse->count( face ))
+ continue;
+ if ( SMESH_MeshAlgos::FaceNormal( face, norm, /*normalized=*/true ))
+ {
+ norms.push_back( norm );
+ avgNorm += norm;
+ if ( !alongAvgNorm )
+ {
+ gp_XYZ bc(0,0,0);
+ int nbN = 0;
+ for ( SMDS_ElemIteratorPtr nIt = face->nodesIterator(); nIt->more(); ++nbN )
+ bc += SMESH_NodeXYZ( nIt->next() );
+ baryCenters.push_back( bc / nbN );
+ }
}
}
- else {
- if ( aT2 > aT1 ) {
- aPrms.reverse();
- }
- }
- // 3. Path Points
- SMESH_MeshEditor_PathPoint aPP;
- 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 );
- aPP.SetPnt( aP3D );
- aPP.SetTangent( aTgt );
- aPP.SetParameter( aT );
- LPP.push_back(aPP);
- }
- return EXTR_OK;
-}
+ if ( norms.empty() ) return 0;
-//=======================================================================
-//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;
- }
+ double normSize = avgNorm.Modulus();
+ if ( normSize < std::numeric_limits<double>::min() )
+ return 0;
- 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;
+ if ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ) // extrude along avgNorm
+ {
+ myDir = avgNorm;
+ return makeNodesByDir( mesh, srcNode, newNodes, makeMediumNodes );
+ }
- // 3. Center of rotation aV0
- gp_Pnt aV0 = theRefPoint;
- gp_XYZ aGC;
- if ( !theHasRefPoint ) {
- aNb = 0;
- aGC.SetCoord( 0.,0.,0. );
+ avgNorm /= normSize;
- itElem = theElements.begin();
- for ( ; itElem != theElements.end(); itElem++ ) {
- const SMDS_MeshElement* elem = *itElem;
+ int nbNodes = 0;
+ for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
+ {
+ gp_XYZ pNew = p;
+ double stepSize = nextStep();
- 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 ( norms.size() > 1 )
+ {
+ for ( size_t iF = 0; iF < norms.size(); ++iF ) // loop on faces
+ {
+ // translate plane of a face
+ baryCenters[ iF ] += norms[ iF ] * stepSize;
- if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
- list<const SMDS_MeshNode*> aLNx;
- mapNewNodes[node] = aLNx;
- //
- gp_XYZ aXYZ( aX, aY, aZ );
- aGC += aXYZ;
- ++aNb;
- }
+ // find point of intersection of the face plane located at baryCenters[ iF ]
+ // and avgNorm located at pNew
+ double d = -( norms[ iF ] * baryCenters[ iF ]); // d of plane equation ax+by+cz+d=0
+ double dot = ( norms[ iF ] * avgNorm );
+ if ( dot < std::numeric_limits<double>::min() )
+ dot = stepSize * 1e-3;
+ double step = -( norms[ iF ] * pNew + d ) / dot;
+ pNew += step * avgNorm;
}
}
- aGC /= aNb;
- aV0.SetXYZ( aGC );
- } // if (!theHasRefPoint) {
- mapNewNodes.clear();
-
- // 4. Processing the elements
- SMESHDS_Mesh* aMesh = GetMeshDS();
+ else
+ {
+ pNew += stepSize * avgNorm;
+ }
+ p = pNew;
- for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
- // check element type
- const SMDS_MeshElement* elem = *itElem;
- aTypeE = elem->GetType();
- if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
- continue;
+ const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
+ newNodes.push_back( newNode );
+ }
+ return nbNodes;
+}
- vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
- newNodesItVec.reserve( elem->NbNodes() );
+//=======================================================================
+//function : ExtrusParam::makeNodesByNormal1D
+//purpose : create nodes for extrusion using normals of edges
+//=======================================================================
- // loop on elem nodes
- int nodeIndex = -1;
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() )
- {
- ++nodeIndex;
- // check if a node has been already processed
- const SMDS_MeshNode* node =
- 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;
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByNormal1D( SMESHDS_Mesh* /*mesh*/,
+ const SMDS_MeshNode* /*srcNode*/,
+ std::list<const SMDS_MeshNode*> & /*newNodes*/,
+ const bool /*makeMediumNodes*/)
+{
+ throw SALOME_Exception("Extrusion 1D by Normal not implemented");
+ return 0;
+}
- // make new nodes
- aX = node->X(); aY = node->Y(); aZ = node->Z();
+//=======================================================================
+//function : ExtrusParam::makeNodesAlongTrack
+//purpose : create nodes for extrusion along path
+//=======================================================================
- Standard_Real aAngle1x, aAngleT1T0, aTolAng;
- gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
- gp_Ax1 anAx1, anAxT1T0;
- gp_Dir aDT1x, aDT0x, aDT1T0;
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesAlongTrack( SMESHDS_Mesh* mesh,
+ const SMDS_MeshNode* srcNode,
+ std::list<const SMDS_MeshNode*> & newNodes,
+ const bool makeMediumNodes)
+{
+ const Standard_Real aTolAng=1.e-4;
- aTolAng=1.e-4;
+ gp_Pnt aV0x = myBaseP;
+ gp_Pnt aPN0 = SMESH_NodeXYZ( srcNode );
- aV0x = aV0;
- aPN0.SetCoord(aX, aY, aZ);
+ const PathPoint& aPP0 = myPathPoints[0];
+ gp_Pnt aP0x = aPP0.myPnt;
+ gp_Dir aDT0x= aPP0.myTgt;
- 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;
+ std::vector< gp_Pnt > centers;
+ centers.reserve( NbSteps() * 2 );
- 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;
- gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
- // Translation
- gp_Vec aV01x( aP0x, aP1x );
- aTrsf.SetTranslation( aV01x );
+ for ( size_t j = 1; j < myPathPoints.size(); ++j )
+ {
+ const PathPoint& aPP = myPathPoints[j];
+ const gp_Pnt& aP1x = aPP.myPnt;
+ const gp_Dir& aDT1x = aPP.myTgt;
- // traslated point
- aV1x = aV0x.Transformed( aTrsf );
- aPN1 = aPN0.Transformed( aTrsf );
+ // Translation
+ gp_Vec aV01x( aP0x, aP1x );
+ aTrsf.SetTranslation( aV01x );
+ gp_Pnt aV1x = aV0x.Transformed( aTrsf );
+ gp_Pnt 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 );
+ // rotation 1 [ T1,T0 ]
+ Standard_Real aAngleT1T0 = -aDT1x.Angle( aDT0x );
+ if ( fabs( aAngleT1T0 ) > aTolAng )
+ {
+ gp_Dir aDT1T0 = aDT1x ^ aDT0x;
+ aTrsfRotT1T0.SetRotation( gp_Ax1( aV1x, aDT1T0 ), aAngleT1T0 );
- aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
- }
+ aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
+ }
- // rotation 2
- if ( theHasAngles ) {
- anAx1.SetLocation( aV1x );
- anAx1.SetDirection( aDT1x );
- aTrsfRot.SetRotation( anAx1, aAngle1x );
+ // rotation 2
+ if ( aPP.myAngle != 0. )
+ {
+ aTrsfRot.SetRotation( gp_Ax1( aV1x, aDT1x ), aPP.myAngle );
+ aPN1 = aPN1.Transformed( aTrsfRot );
+ }
- aPN1 = aPN1.Transformed( aTrsfRot );
- }
+ // make new node
+ if ( makeMediumNodes )
+ {
+ // create additional node
+ gp_XYZ midP = 0.5 * ( aPN1.XYZ() + aPN0.XYZ() );
+ const SMDS_MeshNode* newNode = mesh->AddNode( midP.X(), midP.Y(), midP.Z() );
+ newNodes.push_back( newNode );
- // 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 y = ( aPN1.Y() + aPN0.Y() )/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 );
- myLastCreatedNodes.Append(newNode);
- srcNodes.Append( node );
- listNewNodes.push_back( newNode );
+ }
+ const SMDS_MeshNode* newNode = mesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() );
+ newNodes.push_back( newNode );
- aPN0 = aPN1;
- aP0x = aP1x;
- aV0x = aV1x;
- aDT0x = aDT1x;
- }
- }
+ centers.push_back( 0.5 * ( aV0x.XYZ() + aV1x.XYZ() ));
+ centers.push_back( aV1x );
- 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()==aNbTP-1) {
- vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
- gp_XYZ P(node->X(), node->Y(), node->Z());
- list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
- int i;
- for(i=0; i<aNbTP-1; i++) {
- const SMDS_MeshNode* N = *it;
- double x = ( N->X() + P.X() )/2.;
- 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;
- P = gp_XYZ(N->X(),N->Y(),N->Z());
- }
- listNewNodes.clear();
- for(i=0; i<2*(aNbTP-1); i++) {
- listNewNodes.push_back(aNodes[i]);
- }
- }
- }
- }
+ aPN0 = aPN1;
+ aP0x = aP1x;
+ aV0x = aV1x;
+ aDT0x = aDT1x;
+ }
- newNodesItVec.push_back( nIt );
+ // scale
+ if ( !myScales.empty() )
+ {
+ gp_Trsf aTrsfScale;
+ std::list<const SMDS_MeshNode*>::iterator node = newNodes.begin();
+ for ( size_t i = !makeMediumNodes;
+ i < myScales.size() && node != newNodes.end();
+ i += ( 1 + !makeMediumNodes ), ++node )
+ {
+ aTrsfScale.SetScale( centers[ i ], myScales[ i ] );
+ gp_Pnt aN = SMESH_NodeXYZ( *node );
+ gp_Pnt aP = aN.Transformed( aTrsfScale );
+ mesh->MoveNode( *node, aP.X(), aP.Y(), aP.Z() );
}
- // make new elements
- //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
- // newNodesItVec[0]->second.size(), myLastCreatedElems );
- sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
}
- makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
+ return myPathPoints.size() + makeMediumNodes * ( myPathPoints.size() - 2 );
+}
- if ( theMakeGroups )
- generateGroups( srcNodes, srcElems, "extruded");
+//=======================================================================
+//function : ExtrusionSweep
+//purpose :
+//=======================================================================
- return EXTR_OK;
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElems[2],
+ const gp_Vec& theStep,
+ const int theNbSteps,
+ TTElemOfElemListMap& newElemsMap,
+ const int theFlags,
+ const double theTolerance)
+{
+ std::list<double> dummy;
+ ExtrusParam aParams( theStep, theNbSteps, dummy, dummy, 0,
+ theFlags, theTolerance );
+ return ExtrusionSweep( theElems, aParams, newElemsMap );
}
+namespace
+{
//=======================================================================
-//function : LinearAngleVariation
-//purpose : auxilary for ExtrusionAlongTrack
+//function : getOriFactor
+//purpose : Return -1 or 1 depending on if order of given nodes corresponds to
+// edge curve orientation
//=======================================================================
-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 );
+ double getOriFactor( const TopoDS_Edge& edge,
+ const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ SMESH_MesherHelper& helper)
+ {
+ double u1 = helper.GetNodeU( edge, n1, n2 );
+ double u2 = helper.GetNodeU( edge, n2, n1 );
+ return u1 < u2 ? 1. : -1.;
}
}
-
-//================================================================================
-/*!
- * \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
- * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
- */
-//================================================================================
+//=======================================================================
+//function : ExtrusionSweep
+//purpose :
+//=======================================================================
SMESH_MeshEditor::PGroupIDs
-SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
- const gp_Trsf& theTrsf,
- const bool theCopy,
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2],
+ ExtrusParam& theParams,
+ TTElemOfElemListMap& newElemsMap)
+{
+ ClearLastCreated();
+
+ setElemsFirst( theElemSets );
+ myLastCreatedElems.reserve( theElemSets[0].size() * theParams.NbSteps() );
+ myLastCreatedNodes.reserve( theElemSets[1].size() * theParams.NbSteps() );
+
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+ srcElems.reserve( theElemSets[0].size() );
+ srcNodes.reserve( theElemSets[1].size() );
+
+ const int nbSteps = theParams.NbSteps();
+ theParams.SetElementsToUse( theElemSets[0], theElemSets[1] );
+
+ TNodeOfNodeListMap mapNewNodes;
+ TElemOfVecOfNnlmiMap mapElemNewNodes;
+
+ const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
+ myMesh->NbFaces(ORDER_QUADRATIC) +
+ myMesh->NbVolumes(ORDER_QUADRATIC) );
+ // loop on theElems
+ TIDSortedElemSet::iterator itElem;
+ for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+ {
+ TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+ {
+ // check element type
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() == SMDSAbs_Volume )
+ continue;
+
+ const size_t nbNodes = elem->NbNodes();
+ vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+ newNodesItVec.reserve( nbNodes );
+
+ // loop on elem nodes
+ SMDS_NodeIteratorPtr itN = elem->nodeIterator();
+ while ( itN->more() )
+ {
+ // check if a node has been already sweeped
+ const SMDS_MeshNode* node = itN->next();
+ TNodeOfNodeListMap::iterator nIt =
+ mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+ list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+ if ( listNewNodes.empty() )
+ {
+ // make new nodes
+
+ // check if we are to create medium nodes between corner ones
+ bool needMediumNodes = false;
+ if ( isQuadraticMesh )
+ {
+ SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
+ while (it->more() && !needMediumNodes )
+ {
+ const SMDS_MeshElement* invElem = it->next();
+ if ( invElem != elem && !theElems.count( invElem )) continue;
+ needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
+ if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+ needMediumNodes = true;
+ }
+ }
+ // create nodes for all steps
+ if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes ))
+ {
+ list<const SMDS_MeshNode*>::iterator newNodesIt = listNewNodes.begin();
+ for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt )
+ {
+ myLastCreatedNodes.push_back( *newNodesIt );
+ srcNodes.push_back( node );
+ }
+ }
+ else
+ {
+ if ( theParams.ToMakeBoundary() )
+ {
+ GetMeshDS()->Modified();
+ throw SALOME_Exception( SMESH_Comment("Can't extrude node #") << node->GetID() );
+ }
+ break; // newNodesItVec will be shorter than nbNodes
+ }
+ }
+ newNodesItVec.push_back( nIt );
+ }
+ // make new elements
+ if ( newNodesItVec.size() == nbNodes )
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems );
+ }
+ }
+
+ if ( theParams.ToMakeBoundary() ) {
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems );
+ }
+ PGroupIDs newGroupIDs;
+ if ( theParams.ToMakeGroups() )
+ newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
+
+ return newGroupIDs;
+}
+
+//=======================================================================
+//function : ExtrusionAlongTrack
+//purpose :
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
+ SMESH_Mesh* theTrackMesh,
+ SMDS_ElemIteratorPtr theTrackIterator,
+ const SMDS_MeshNode* theN1,
+ std::list<double>& theAngles,
+ const bool theAngleVariation,
+ std::list<double>& theScales,
+ const bool theScaleVariation,
+ const gp_Pnt* theRefPoint,
+ const bool theMakeGroups)
+{
+ ClearLastCreated();
+
+ // 1. Check data
+ if ( theElements[0].empty() && theElements[1].empty() )
+ return EXTR_NO_ELEMENTS;
+
+ ASSERT( theTrackMesh );
+ if ( ! theTrackIterator || !theTrackIterator->more() )
+ return EXTR_NO_ELEMENTS;
+
+ // 2. Get ordered nodes
+ SMESH_MeshAlgos::TElemGroupVector branchEdges;
+ SMESH_MeshAlgos::TNodeGroupVector branchNods;
+ SMESH_MeshAlgos::Get1DBranches( theTrackIterator, branchEdges, branchNods, theN1 );
+ if ( branchEdges.empty() )
+ return EXTR_PATH_NOT_EDGE;
+
+ if ( branchEdges.size() > 1 )
+ return EXTR_BAD_PATH_SHAPE;
+
+ std::vector< const SMDS_MeshNode* >& pathNodes = branchNods[0];
+ std::vector< const SMDS_MeshElement* >& pathEdges = branchEdges[0];
+ if ( pathNodes[0] != theN1 && pathNodes[1] != theN1 )
+ return EXTR_BAD_STARTING_NODE;
+
+ if ( theTrackMesh->NbEdges( ORDER_QUADRATIC ) > 0 )
+ {
+ // add medium nodes to pathNodes
+ std::vector< const SMDS_MeshNode* > pathNodes2;
+ std::vector< const SMDS_MeshElement* > pathEdges2;
+ pathNodes2.reserve( pathNodes.size() * 2 );
+ pathEdges2.reserve( pathEdges.size() * 2 );
+ for ( size_t i = 0; i < pathEdges.size(); ++i )
+ {
+ pathNodes2.push_back( pathNodes[i] );
+ pathEdges2.push_back( pathEdges[i] );
+ if ( pathEdges[i]->IsQuadratic() )
+ {
+ pathNodes2.push_back( pathEdges[i]->GetNode(2) );
+ pathEdges2.push_back( pathEdges[i] );
+ }
+ }
+ pathNodes2.push_back( pathNodes.back() );
+ pathEdges.swap( pathEdges2 );
+ pathNodes.swap( pathNodes2 );
+ }
+
+ // 3. Get path data at pathNodes
+
+ std::vector< ExtrusParam::PathPoint > points( pathNodes.size() );
+
+ if ( theAngleVariation )
+ linearAngleVariation( points.size()-1, theAngles );
+ if ( theScaleVariation )
+ linearScaleVariation( points.size()-1, theScales );
+
+ theAngles.push_front( 0 ); // for the 1st point that is not transformed
+ std::list<double>::iterator angle = theAngles.begin();
+
+ SMESHDS_Mesh* pathMeshDS = theTrackMesh->GetMeshDS();
+
+ std::map< int, double > edgeID2OriFactor; // orientation of EDGEs
+ std::map< int, double >::iterator id2factor;
+ SMESH_MesherHelper pathHelper( *theTrackMesh );
+ gp_Pnt p; gp_Vec tangent;
+ const double tol2 = gp::Resolution() * gp::Resolution();
+
+ for ( size_t i = 0; i < pathNodes.size(); ++i )
+ {
+ ExtrusParam::PathPoint & point = points[ i ];
+
+ point.myPnt = SMESH_NodeXYZ( pathNodes[ i ]);
+
+ if ( angle != theAngles.end() )
+ point.myAngle = *angle++;
+
+ tangent.SetCoord( 0,0,0 );
+ const int shapeID = pathNodes[ i ]->GetShapeID();
+ const TopoDS_Shape& shape = pathMeshDS->IndexToShape( shapeID );
+ TopAbs_ShapeEnum shapeType = shape.IsNull() ? TopAbs_SHAPE : shape.ShapeType();
+ switch ( shapeType )
+ {
+ case TopAbs_EDGE:
+ {
+ TopoDS_Edge edge = TopoDS::Edge( shape );
+ id2factor = edgeID2OriFactor.insert( std::make_pair( shapeID, 0 )).first;
+ if ( id2factor->second == 0 )
+ {
+ if ( i ) id2factor->second = getOriFactor( edge, pathNodes[i-1], pathNodes[i], pathHelper );
+ else id2factor->second = getOriFactor( edge, pathNodes[i], pathNodes[i+1], pathHelper );
+ }
+ double u = pathHelper.GetNodeU( edge, pathNodes[i] ), u0, u1;
+ Handle(Geom_Curve) curve = BRep_Tool::Curve( edge, u0, u1 );
+ curve->D1( u, p, tangent );
+ tangent *= id2factor->second;
+ break;
+ }
+ case TopAbs_VERTEX:
+ {
+ int nbEdges = 0;
+ PShapeIteratorPtr shapeIt = pathHelper.GetAncestors( shape, *theTrackMesh, TopAbs_EDGE );
+ while ( const TopoDS_Shape* edgePtr = shapeIt->next() )
+ {
+ int edgeID = pathMeshDS->ShapeToIndex( *edgePtr );
+ for ( int di = -1; di <= 0; ++di )
+ {
+ size_t j = i + di;
+ if ( j < pathEdges.size() && edgeID == pathEdges[ j ]->GetShapeID() )
+ {
+ TopoDS_Edge edge = TopoDS::Edge( *edgePtr );
+ id2factor = edgeID2OriFactor.insert( std::make_pair( edgeID, 0 )).first;
+ if ( id2factor->second == 0 )
+ {
+ if ( j < i )
+ id2factor->second = getOriFactor( edge, pathNodes[i-1], pathNodes[i], pathHelper );
+ else
+ id2factor->second = getOriFactor( edge, pathNodes[i], pathNodes[i+1], pathHelper );
+ }
+ double u = pathHelper.GetNodeU( edge, pathNodes[i] ), u0, u1;
+ Handle(Geom_Curve) curve = BRep_Tool::Curve( edge, u0, u1 );
+ gp_Vec du;
+ curve->D1( u, p, du );
+ double size2 = du.SquareMagnitude();
+ if ( du.SquareMagnitude() > tol2 )
+ {
+ tangent += du.Divided( Sqrt( size2 )) * id2factor->second;
+ nbEdges++;
+ }
+ break;
+ }
+ }
+ }
+ if ( nbEdges > 0 )
+ break;
+ }
+ // fall through
+ default:
+ {
+ for ( int di = -1; di <= 1; di += 2 )
+ {
+ size_t j = i + di;
+ if ( j < pathNodes.size() )
+ {
+ gp_Vec dir( point.myPnt, SMESH_NodeXYZ( pathNodes[ j ]));
+ double size2 = dir.SquareMagnitude();
+ if ( size2 > tol2 )
+ tangent += dir.Divided( Sqrt( size2 )) * di;
+ }
+ }
+ }
+ } // switch ( shapeType )
+
+ if ( tangent.SquareMagnitude() < tol2 )
+ return EXTR_CANT_GET_TANGENT;
+
+ point.myTgt = tangent;
+
+ } // loop on pathNodes
+
+
+ ExtrusParam nodeMaker( points, theRefPoint, theScales, theMakeGroups );
+ TTElemOfElemListMap newElemsMap;
+
+ ExtrusionSweep( theElements, nodeMaker, newElemsMap );
+
+ return EXTR_OK;
+}
+
+//=======================================================================
+//function : linearAngleVariation
+//purpose : spread values over nbSteps
+//=======================================================================
+
+void SMESH_MeshEditor::linearAngleVariation(const int nbSteps,
+ list<double>& Angles)
+{
+ int nbAngles = Angles.size();
+ if( nbSteps > nbAngles && nbAngles > 0 )
+ {
+ vector<double> theAngles(nbAngles);
+ theAngles.assign( Angles.begin(), Angles.end() );
+
+ 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.swap( res );
+ }
+}
+
+//=======================================================================
+//function : linearScaleVariation
+//purpose : spread values over nbSteps
+//=======================================================================
+
+void SMESH_MeshEditor::linearScaleVariation(const int theNbSteps,
+ std::list<double>& theScales)
+{
+ int nbScales = theScales.size();
+ std::vector<double> myScales;
+ myScales.reserve( theNbSteps );
+ std::list<double>::const_iterator scale = theScales.begin();
+ double prevScale = 1.0;
+ for ( int iSc = 1; scale != theScales.end(); ++scale, ++iSc )
+ {
+ int iStep = int( iSc / double( nbScales ) * theNbSteps + 0.5 );
+ int stDelta = Max( 1, iStep - myScales.size());
+ double scDelta = ( *scale - prevScale ) / stDelta;
+ for ( int iStep = 0; iStep < stDelta; ++iStep )
+ {
+ myScales.push_back( prevScale + scDelta );
+ prevScale = myScales.back();
+ }
+ prevScale = *scale;
+ }
+ theScales.assign( myScales.begin(), myScales.end() );
+}
+
+//================================================================================
+/*!
+ * \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
+ * \return 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();
+ ClearLastCreated();
+ myLastCreatedElems.reserve( theElems.size() );
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";
}
- SMESH_MeshEditor targetMeshEditor( theTargetMesh );
SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
SMESHDS_Mesh* aMesh = GetMeshDS();
+ SMESH_MeshEditor targetMeshEditor( theTargetMesh );
+ SMESH_MeshEditor* editor = theTargetMesh ? & targetMeshEditor : theCopy ? this : 0;
+ SMESH_MeshEditor::ElemFeatures elemType;
// map old node to new one
TNodeNodeMap nodeMap;
// loop on elements to transform nodes : first orphan nodes then elems
TIDSortedElemSet::iterator itElem;
- TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
+ 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;
-
- // loop on elem nodes
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() ) {
-
- const SMDS_MeshNode* node = cast2Node( itN->next() );
- // check if a node has been already transformed
- pair<TNodeNodeMap::iterator,bool> n2n_isnew =
- nodeMap.insert( make_pair ( node, node ));
- if ( !n2n_isnew.second )
+ for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ )
+ {
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem )
continue;
+ // loop on elem nodes
double coord[3];
- coord[0] = node->X();
- coord[1] = node->Y();
- coord[2] = node->Z();
- theTrsf.Transforms( 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] );
- // node position on shape becomes invalid
- const_cast< SMDS_MeshNode* > ( node )->SetPosition
- ( SMDS_SpacePosition::originSpacePosition() );
- }
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
+ {
+ const SMDS_MeshNode* node = cast2Node( itN->next() );
+ // check if a node has been already transformed
+ pair<TNodeNodeMap::iterator,bool> n2n_isnew =
+ nodeMap.insert( make_pair ( node, node ));
+ if ( !n2n_isnew.second )
+ continue;
- // keep inverse elements
- if ( !theCopy && !theTargetMesh && needReverse ) {
- SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
- while ( invElemIt->more() ) {
- const SMDS_MeshElement* iel = invElemIt->next();
- inverseElemSet.insert( iel );
+ node->GetXYZ( coord );
+ theTrsf.Transforms( 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.push_back(newNode);
+ srcNodes.push_back( node );
+ }
+ else if ( theCopy ) {
+ const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ n2n_isnew.first->second = newNode;
+ myLastCreatedNodes.push_back(newNode);
+ srcNodes.push_back( node );
+ }
+ else {
+ aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
+ // 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 );
+ }
}
}
- }
- }
+ } // loop on elems in { &orphanNode, &theElems };
// either create new elements or reverse mirrored ones
if ( !theCopy && !needReverse && !theTargetMesh )
return PGroupIDs();
- TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
- for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
- theElems.insert( *invElemIt );
+ theElems.insert( inverseElemSet.begin(),inverseElemSet.end() );
// Replicate or reverse elements
std::vector<int> iForw;
+ vector<const SMDS_MeshNode*> nodes;
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
{
const SMDS_MeshElement* elem = *itElem;
if ( !elem ) continue;
SMDSAbs_GeometryType geomType = elem->GetGeomType();
- int nbNodes = elem->NbNodes();
+ size_t nbNodes = elem->NbNodes();
if ( geomType == SMDSGeom_NONE ) continue; // node
- switch ( geomType ) {
+ nodes.resize( nbNodes );
- case SMDSGeom_POLYGON: // ---------------------- polygon
+ if ( geomType == SMDSGeom_POLYHEDRA ) // ------------------ polyhedral volume
+ {
+ const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( elem );
+ if ( !aPolyedre )
+ continue;
+ nodes.clear();
+ bool allTransformed = true;
+ int nbFaces = aPolyedre->NbFaces();
+ for (int iface = 1; iface <= nbFaces && allTransformed; iface++)
{
- 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());
+ 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())
- 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 ( nodeMapIt == nodeMap.end() )
+ allTransformed = false; // not all nodes transformed
+ else
+ nodes.push_back((*nodeMapIt).second);
}
- if ( iNode != nbNodes )
- continue; // not all nodes transformed
+ if ( needReverse && allTransformed )
+ std::reverse( nodes.end() - nbFaceNodes, nodes.end() );
+ }
+ if ( !allTransformed )
+ continue; // not all nodes transformed
+ }
+ else // ----------------------- the rest element types
+ {
+ while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
+ const vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType(), nbNodes );
+ const vector<int>& i = needReverse ? iRev : iForw;
- 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);
- }
+ // find transformed nodes
+ size_t 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;
}
- break;
+ if ( iNode != nbNodes )
+ continue; // not all nodes transformed
+ }
- case SMDSGeom_POLYHEDRA: // ------------------ polyhedral volume
- {
- const SMDS_VtkVolume* aPolyedre =
- dynamic_cast<const SMDS_VtkVolume*>( elem );
- if (!aPolyedre) {
- MESSAGE("Warning: bad volumic element");
- continue;
- }
+ if ( editor ) {
+ // copy in this or a new mesh
+ if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false )))
+ srcElems.push_back( elem );
+ }
+ else {
+ // reverse element as it was reversed by transformation
+ if ( nbNodes > 2 )
+ aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+ }
- vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
- vector<int> quantities; quantities.reserve( nbNodes );
-
- 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);
- }
- if ( needReverse && allTransformed )
- std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
- }
- quantities.push_back(nbFaceNodes);
- }
- if ( !allTransformed )
- continue; // not all nodes transformed
+ } // loop on elements
- 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;
+ if ( editor && editor != this )
+ myLastCreatedElems.swap( editor->myLastCreatedElems );
- case SMDSGeom_BALL: // -------------------- Ball
- {
- if ( !theCopy && !theTargetMesh ) continue;
+ PGroupIDs newGroupIDs;
- TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
- if (nodeMapIt == nodeMap.end())
- continue; // not all nodes transformed
+ if ( ( theMakeGroups && theCopy ) ||
+ ( theMakeGroups && theTargetMesh ) )
+ newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false );
- double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
- if ( theTargetMesh ) {
- myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
- srcElems.Append( elem );
- }
- else {
- myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
- srcElems.Append( elem );
- }
- }
- break;
+ return newGroupIDs;
+}
- default: // ----------------------- Regular elements
+//================================================================================
+/*!
+ * \brief Make an offset mesh from a source 2D mesh
+ * \param [in] theElements - source faces
+ * \param [in] theValue - offset value
+ * \param [out] theTgtMesh - a mesh to add offset elements to
+ * \param [in] theMakeGroups - to generate groups
+ * \return PGroupIDs - IDs of created groups. NULL means failure
+ */
+//================================================================================
- while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
- const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
- const std::vector<int>& i = needReverse ? iRev : iForw;
+SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElements,
+ const double theValue,
+ SMESH_Mesh* theTgtMesh,
+ const bool theMakeGroups,
+ const bool theCopyElements,
+ const bool theFixSelfIntersection)
+{
+ SMESHDS_Mesh* meshDS = GetMeshDS();
+ SMESHDS_Mesh* tgtMeshDS = theTgtMesh->GetMeshDS();
+ SMESH_MeshEditor tgtEditor( theTgtMesh );
- // 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
+ SMDS_ElemIteratorPtr eIt;
+ if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face );
+ else eIt = SMESHUtils::elemSetIterator( theElements );
- if ( theTargetMesh ) {
- if ( SMDS_MeshElement* copy =
- targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
- myLastCreatedElems.Append( copy );
- srcElems.Append( elem );
- }
- }
- else if ( theCopy ) {
- if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
- srcElems.Append( elem );
+ SMESH_MeshAlgos::TElemIntPairVec new2OldFaces;
+ SMESH_MeshAlgos::TNodeIntPairVec new2OldNodes;
+ std::unique_ptr< SMDS_Mesh > offsetMesh
+ ( SMESH_MeshAlgos::MakeOffset( eIt, *meshDS, theValue,
+ theFixSelfIntersection,
+ new2OldFaces, new2OldNodes ));
+ if ( offsetMesh->NbElements() == 0 )
+ return PGroupIDs(); // MakeOffset() failed
+
+
+ if ( theTgtMesh == myMesh && !theCopyElements )
+ {
+ // clear the source elements
+ if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face );
+ else eIt = SMESHUtils::elemSetIterator( theElements );
+ while ( eIt->more() )
+ meshDS->RemoveFreeElement( eIt->next(), 0 );
+ }
+
+ // offsetMesh->Modified();
+ // offsetMesh->CompactMesh(); // make IDs start from 1
+
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+ srcElems.reserve( new2OldFaces.size() );
+ srcNodes.reserve( new2OldNodes.size() );
+
+ ClearLastCreated();
+ myLastCreatedElems.reserve( new2OldFaces.size() );
+ myLastCreatedNodes.reserve( new2OldNodes.size() );
+
+ // copy offsetMesh to theTgtMesh
+
+ smIdType idShift = meshDS->MaxNodeID();
+ for ( size_t i = 0; i < new2OldNodes.size(); ++i )
+ if ( const SMDS_MeshNode* n = new2OldNodes[ i ].first )
+ {
+#ifndef _DEBUG_
+ if ( n->NbInverseElements() > 0 )
+#endif
+ {
+ const SMDS_MeshNode* n2 =
+ tgtMeshDS->AddNodeWithID( n->X(), n->Y(), n->Z(), idShift + n->GetID() );
+ myLastCreatedNodes.push_back( n2 );
+ srcNodes.push_back( meshDS->FindNode( new2OldNodes[ i ].second ));
}
- else {
- // reverse element as it was reversed by transformation
- if ( nbNodes > 2 )
- aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+ }
+
+ ElemFeatures elemType;
+ for ( size_t i = 0; i < new2OldFaces.size(); ++i )
+ if ( const SMDS_MeshElement* f = new2OldFaces[ i ].first )
+ {
+ elemType.Init( f );
+ elemType.myNodes.clear();
+ for ( SMDS_NodeIteratorPtr nIt = f->nodeIterator(); nIt->more(); )
+ {
+ const SMDS_MeshNode* n2 = nIt->next();
+ elemType.myNodes.push_back( tgtMeshDS->FindNode( idShift + n2->GetID() ));
}
- } // switch ( geomType )
+ tgtEditor.AddElement( elemType.myNodes, elemType );
+ srcElems.push_back( meshDS->FindElement( new2OldFaces[ i ].second ));
+ }
- } // loop on elements
+ myLastCreatedElems.swap( tgtEditor.myLastCreatedElems );
PGroupIDs newGroupIDs;
-
- if ( ( theMakeGroups && theCopy ) ||
- ( theMakeGroups && theTargetMesh ) )
- newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+ if ( theMakeGroups )
+ newGroupIDs = generateGroups( srcNodes, srcElems, "offset", theTgtMesh, false );
+ else
+ newGroupIDs.reset( new std::list< int > );
return newGroupIDs;
}
//=======================================================================
/*!
* \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
+ * \param nodeGens - nodes making corresponding myLastCreatedNodes
+ * \param elemGens - elements making corresponding myLastCreatedElems
+ * \param postfix - to push_back to names of new groups
+ * \param targetMesh - mesh to create groups in
+ * \param topPresent - is there are "top" elements that are created by sweeping
*/
//=======================================================================
SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
const SMESH_SequenceOfElemPtr& elemGens,
const std::string& postfix,
- SMESH_Mesh* targetMesh)
+ SMESH_Mesh* targetMesh,
+ const bool topPresent)
{
PGroupIDs newGroupIDs( new list<int> );
SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
// Sort existing groups by types and collect their names
- // to store an old group and a generated new ones
+ // containers to store an old group and generated new ones;
+ // 1st new group is for result elems of different type than a source one;
+ // 2nd new group is for same type result elems ("top" group at extrusion)
using boost::tuple;
using boost::make_tuple;
typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
// Loop on nodes and elements to add them in new groups
+ vector< const SMDS_MeshElement* > resultElems;
for ( int isNodes = 0; isNodes < 2; ++isNodes )
{
const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
- if ( gens.Length() != elems.Length() )
+ if ( gens.size() != elems.size() )
throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
// loop on created elements
- for (int iElem = 1; iElem <= elems.Length(); ++iElem )
+ for (size_t iElem = 0; iElem < elems.size(); ++iElem )
{
- const SMDS_MeshElement* sourceElem = gens( iElem );
+ const SMDS_MeshElement* sourceElem = gens[ iElem ];
if ( !sourceElem ) {
MESSAGE("generateGroups(): NULL source element");
continue;
}
list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
if ( groupsOldNew.empty() ) { // no groups of this type at all
- while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
+ while ( iElem+1 < gens.size() && gens[ iElem+1 ] == sourceElem )
++iElem; // skip all elements made by sourceElem
continue;
}
// collect all elements made by the iElem-th sourceElem
- list< const SMDS_MeshElement* > resultElems;
- if ( const SMDS_MeshElement* resElem = elems( iElem ))
+ resultElems.clear();
+ 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 ))
+ while ( iElem+1 < gens.size() && gens[ iElem+1 ] == sourceElem )
+ if ( const SMDS_MeshElement* resElem = elems[ ++iElem ])
if ( resElem != sourceElem )
resultElems.push_back( resElem );
- // there must be a top element
const SMDS_MeshElement* topElem = 0;
- if ( isNodes )
+ if ( isNodes ) // there must be a top element
{
topElem = resultElems.back();
resultElems.pop_back();
}
else
{
- list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
+ vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
if ( (*resElemIt)->GetType() == sourceElem->GetType() )
{
topElem = *resElemIt;
- resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt
+ *resElemIt = 0; // erase *resElemIt
break;
}
}
-
// add resultElems to groups originted from ones the sourceElem belongs to
list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
{
// fill in a new group
SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
- list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
+ vector< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
- newGroup.Add( *resElemIt );
+ if ( *resElemIt )
+ newGroup.Add( *resElemIt );
// fill a "top" group
if ( topElem )
SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>();
SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
orderedOldNewGroups[i]->get<2>() };
- const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
for ( int is2nd = 0; is2nd < 2; ++is2nd )
{
SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
// make a name
- const bool isTop = ( nbNewGroups == 2 &&
+ const bool isTop = ( topPresent &&
newGroupDS->GetType() == oldGroupDS->GetType() &&
is2nd );
string name = oldGroupDS->GetStoreName();
+ { // remove trailing whitespaces (issue 22599)
+ size_t size = name.size();
+ while ( size > 1 && isspace( name[ size-1 ]))
+ --size;
+ if ( size != name.size() )
+ {
+ name.resize( size );
+ oldGroupDS->SetStoreName( name.c_str() );
+ }
+ }
if ( !targetMesh ) {
string suffix = ( isTop ? "top": postfix.c_str() );
name += "_";
//================================================================================
/*!
- * \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
+ * * \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
+ * \param [in,out] theNodes - the nodes to treat
+ * \param [in] theTolerance - the tolerance
+ * \param [out] theGroupsOfNodes - the result groups of coincident nodes
+ * \param [in] theSeparateCornersAndMedium - if \c true, in quadratic mesh puts
+ * corner and medium nodes in separate groups
*/
//================================================================================
void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
const double theTolerance,
- TListOfListOfNodes & theGroupsOfNodes)
+ TListOfListOfNodes & theGroupsOfNodes,
+ bool theSeparateCornersAndMedium)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
- 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());
+ if ( myMesh->NbEdges ( ORDER_QUADRATIC ) +
+ myMesh->NbFaces ( ORDER_QUADRATIC ) +
+ myMesh->NbVolumes( ORDER_QUADRATIC ) == 0 )
+ theSeparateCornersAndMedium = false;
+
+ TIDSortedNodeSet& corners = theNodes;
+ TIDSortedNodeSet medium;
+
+ if ( theNodes.empty() ) // get all nodes in the mesh
+ {
+ TIDSortedNodeSet* nodes[2] = { &corners, &medium };
+ SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
+ if ( theSeparateCornersAndMedium )
+ while ( nIt->more() )
+ {
+ const SMDS_MeshNode* n = nIt->next();
+ TIDSortedNodeSet* & nodeSet = nodes[ SMESH_MesherHelper::IsMedium( n )];
+ nodeSet->insert( nodeSet->end(), n );
+ }
+ else
+ while ( nIt->more() )
+ theNodes.insert( theNodes.end(), nIt->next() );
+ }
+ else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes
+ {
+ TIDSortedNodeSet::iterator nIt = corners.begin();
+ while ( nIt != corners.end() )
+ if ( SMESH_MesherHelper::IsMedium( *nIt ))
+ {
+ medium.insert( medium.end(), *nIt );
+ corners.erase( nIt++ );
+ }
+ else
+ {
+ ++nIt;
+ }
}
- SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
+ if ( !corners.empty() )
+ SMESH_OctreeNode::FindCoincidentNodes ( corners, &theGroupsOfNodes, theTolerance );
+ if ( !medium.empty() )
+ SMESH_OctreeNode::FindCoincidentNodes ( medium, &theGroupsOfNodes, theTolerance );
}
-
//=======================================================================
-/*!
- * \brief Implementation of search for the node closest to point
- */
+//function : SimplifyFace
+//purpose : split a chain of nodes into several closed chains
//=======================================================================
-struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
+int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
+ vector<const SMDS_MeshNode *>& poly_nodes,
+ vector<int>& quantities) const
{
- //---------------------------------------------------------------------
- /*!
- * \brief Constructor
- */
- SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
- {
- myMesh = ( SMESHDS_Mesh* ) theMesh;
-
- 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) ;
+ int nbNodes = faceNodes.size();
+ while ( faceNodes[ 0 ] == faceNodes[ nbNodes-1 ] && nbNodes > 2 )
+ --nbNodes;
+ if ( nbNodes < 3 )
+ return 0;
+ size_t prevNbQuant = quantities.size();
- // 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.;
- }
+ vector< const SMDS_MeshNode* > simpleNodes; simpleNodes.reserve( nbNodes );
+ map< const SMDS_MeshNode*, int > nodeIndices; // indices within simpleNodes
+ map< const SMDS_MeshNode*, int >::iterator nInd;
- //---------------------------------------------------------------------
- /*!
- * \brief Move node and update myOctreeNode accordingly
- */
- void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
+ nodeIndices.insert( make_pair( faceNodes[0], 0 ));
+ simpleNodes.push_back( faceNodes[0] );
+ for ( int iCur = 1; iCur < nbNodes; iCur++ )
{
- myOctreeNode->UpdateByMoveNode( node, toPnt );
- myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
- }
-
- //---------------------------------------------------------------------
- /*!
- * \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 ( faceNodes[ iCur ] != simpleNodes.back() )
+ {
+ int index = simpleNodes.size();
+ nInd = nodeIndices.insert( make_pair( faceNodes[ iCur ], index )).first;
+ int prevIndex = nInd->second;
+ if ( prevIndex < index )
+ {
+ // a sub-loop found
+ int loopLen = index - prevIndex;
+ if ( loopLen > 2 )
{
- if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
- SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
- while ( cIt->more() )
- treeList.push_back( cIt->next() );
+ // store the sub-loop
+ quantities.push_back( loopLen );
+ for ( int i = prevIndex; i < index; i++ )
+ poly_nodes.push_back( simpleNodes[ i ]);
}
- 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 ));
- }
- }
- // 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 );
+ simpleNodes.resize( prevIndex+1 );
}
- }
- // 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_TNodeXYZ( *nIt ) );
- if ( minSqDist > sqDist ) {
- closestNode = *nIt;
- minSqDist = sqDist;
+ else
+ {
+ simpleNodes.push_back( faceNodes[ iCur ]);
}
}
- return closestNode;
}
- //---------------------------------------------------------------------
- /*!
- * \brief Destructor
- */
- ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
-
- //---------------------------------------------------------------------
- /*!
- * \brief Return the node tree
- */
- const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
+ if ( simpleNodes.size() > 2 )
+ {
+ quantities.push_back( simpleNodes.size() );
+ poly_nodes.insert ( poly_nodes.end(), simpleNodes.begin(), simpleNodes.end() );
+ }
-private:
- SMESH_OctreeNode* myOctreeNode;
- SMESHDS_Mesh* myMesh;
- double myHalfLeafSize; // max size of a leaf box
-};
+ return quantities.size() - prevNbQuant;
+}
//=======================================================================
-/*!
- * \brief Return SMESH_NodeSearcher
- */
+//function : MergeNodes
+//purpose : In each group, the cdr of nodes are substituted by the first one
+// in all elements.
//=======================================================================
-SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
+void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
+ const bool theAvoidMakingHoles)
{
- return new SMESH_NodeSearcherImpl( 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
-
- //=======================================================================
- /*!
- * \brief Octal tree of bounding boxes of elements
- */
- //=======================================================================
+ ClearLastCreated();
- class ElementBndBoxTree : public SMESH_Octree
- {
- public:
+ SMESHDS_Mesh* mesh = GetMeshDS();
- 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);
- void getElementsInSphere ( const gp_XYZ& center,
- const double radius, TIDSortedElemSet& foundElems);
- size_t getSize() { return std::max( _size, _elements.size() ); }
- ~ElementBndBoxTree();
-
- protected:
- ElementBndBoxTree():_size(0) {}
- SMESH_Octree* newChild() 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;
- size_t _size;
- };
+ TNodeNodeMap nodeNodeMap; // node to replace - new node
+ set<const SMDS_MeshElement*> elems; // all elements with changed nodes
+ list< smIdType > rmElemIds, rmNodeIds;
+ vector< ElemFeatures > newElemDefs;
- //================================================================================
- /*!
- * \brief ElementBndBoxTree creation
- */
- //================================================================================
+ // Fill nodeNodeMap and elems
- ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
- :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ))
+ TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
+ for ( ; grIt != theGroupsOfNodes.end(); grIt++ )
{
- 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 ));
-
- compute();
+ list<const SMDS_MeshNode*>& nodes = *grIt;
+ list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
+ const SMDS_MeshNode* nToKeep = *nIt;
+ for ( ++nIt; nIt != nodes.end(); nIt++ )
+ {
+ const SMDS_MeshNode* nToRemove = *nIt;
+ nodeNodeMap.insert( make_pair( nToRemove, nToKeep ));
+ SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
+ while ( invElemIt->more() ) {
+ const SMDS_MeshElement* elem = invElemIt->next();
+ elems.insert(elem);
+ }
+ }
}
- //================================================================================
- /*!
- * \brief Destructor
- */
- //================================================================================
-
- ElementBndBoxTree::~ElementBndBoxTree()
+ // Apply recursive replacements (BUG 0020185)
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.begin();
+ for ( ; nnIt != nodeNodeMap.end(); ++nnIt )
{
- for ( int i = 0; i < _elements.size(); ++i )
- if ( --_elements[i]->_refCount <= 0 )
- delete _elements[i];
+ const SMDS_MeshNode* nToKeep = nnIt->second;
+ TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( nToKeep );
+ while ( nnIt_i != nodeNodeMap.end() && nnIt_i->second != nnIt->second )
+ {
+ nToKeep = nnIt_i->second;
+ nnIt->second = nToKeep;
+ nnIt_i = nodeNodeMap.find( nToKeep );
+ }
}
- //================================================================================
- /*!
- * \brief Return the maximal box
- */
- //================================================================================
-
- Bnd_B3d* ElementBndBoxTree::buildRootBox()
+ if ( theAvoidMakingHoles )
{
- 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
- */
- //================================================================================
+ // find elements whose topology changes
- void ElementBndBoxTree::buildChildrenData()
- {
- for ( int i = 0; i < _elements.size(); ++i )
+ vector<const SMDS_MeshElement*> pbElems;
+ set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
+ for ( ; eIt != elems.end(); ++eIt )
{
- for (int j = 0; j < 8; j++)
+ const SMDS_MeshElement* elem = *eIt;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
{
- if ( !_elements[i]->IsOut( *myChildren[j]->getBox() ))
+ const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
+ if ( nnIt != nodeNodeMap.end() && elem->GetNodeIndex( nnIt->second ) >= 0 )
{
- _elements[i]->_refCount++;
- ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
+ // several nodes of elem stick
+ pbElems.push_back( elem );
+ break;
}
}
- _elements[i]->_refCount--;
}
- _size = _elements.size();
- SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
-
- for (int j = 0; j < 8; j++)
+ // exclude from merge nodes causing spoiling element
+ for ( size_t iLoop = 0; iLoop < pbElems.size(); ++iLoop ) // avoid infinite cycle
{
- ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
- if ( child->_elements.size() <= MaxNbElemsInLeaf )
- child->myIsLeaf = true;
-
- if ( child->_elements.capacity() - child->_elements.size() > 1000 )
- SMESHUtils::CompactVector( child->_elements );
+ bool nodesExcluded = false;
+ for ( size_t i = 0; i < pbElems.size(); ++i )
+ {
+ size_t prevNbMergeNodes = nodeNodeMap.size();
+ if ( !applyMerge( pbElems[i], newElemDefs, nodeNodeMap, /*noHoles=*/true ) &&
+ prevNbMergeNodes < nodeNodeMap.size() )
+ nodesExcluded = true;
+ }
+ if ( !nodesExcluded )
+ break;
}
}
- //================================================================================
- /*!
- * \brief Return elements which can include the point
- */
- //================================================================================
-
- void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
- TIDSortedElemSet& foundElems)
+ for ( nnIt = nodeNodeMap.begin(); nnIt != nodeNodeMap.end(); ++nnIt )
{
- if ( getBox()->IsOut( point.XYZ() ))
- return;
-
- if ( isLeaf() )
- {
- for ( int i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( point.XYZ() ))
- foundElems.insert( _elements[i]->_element );
- }
- else
+ const SMDS_MeshNode* nToRemove = nnIt->first;
+ const SMDS_MeshNode* nToKeep = nnIt->second;
+ if ( nToRemove != nToKeep )
{
- for (int i = 0; i < 8; i++)
- ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
+ rmNodeIds.push_back( nToRemove->GetID() );
+ AddToSameGroups( nToKeep, nToRemove, mesh );
+ // set _alwaysComputed to a sub-mesh of VERTEX to enable further mesh computing
+ // w/o creating node in place of merged ones.
+ SMDS_PositionPtr pos = nToRemove->GetPosition();
+ if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
+ if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
+ sm->SetIsAlwaysComputed( true );
}
}
- //================================================================================
- /*!
- * \brief Return elements which can be intersected by the line
- */
- //================================================================================
+ // Change element nodes or remove an element
- void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
- TIDSortedElemSet& foundElems)
+ set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
+ for ( ; eIt != elems.end(); eIt++ )
{
- if ( getBox()->IsOut( line ))
- return;
+ const SMDS_MeshElement* elem = *eIt;
+ SMESHDS_SubMesh* sm = mesh->MeshElements( elem->getshapeId() );
- if ( isLeaf() )
- {
- for ( int i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( line ))
- foundElems.insert( _elements[i]->_element );
- }
- else
+ bool keepElem = applyMerge( elem, newElemDefs, nodeNodeMap, /*noHoles=*/false );
+ if ( !keepElem )
+ rmElemIds.push_back( elem->GetID() );
+
+ for ( size_t i = 0; i < newElemDefs.size(); ++i )
{
- for (int i = 0; i < 8; i++)
- ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
+ if ( i > 0 || !mesh->ChangeElementNodes( elem,
+ & newElemDefs[i].myNodes[0],
+ newElemDefs[i].myNodes.size() ))
+ {
+ if ( i == 0 )
+ {
+ newElemDefs[i].SetID( elem->GetID() );
+ mesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
+ if ( !keepElem ) rmElemIds.pop_back();
+ }
+ else
+ {
+ newElemDefs[i].SetID( -1 );
+ }
+ SMDS_MeshElement* newElem = this->AddElement( newElemDefs[i].myNodes, newElemDefs[i] );
+ if ( sm && newElem )
+ sm->AddElement( newElem );
+ if ( elem != newElem )
+ ReplaceElemInGroups( elem, newElem, mesh );
+ }
}
}
- //================================================================================
- /*!
- * \brief Return elements from leaves intersecting the sphere
- */
- //================================================================================
+ // Remove bad elements, then equal nodes (order important)
+ Remove( rmElemIds, /*isNodes=*/false );
+ Remove( rmNodeIds, /*isNodes=*/true );
- void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center,
- const double radius,
- TIDSortedElemSet& foundElems)
+ return;
+}
+
+//=======================================================================
+//function : applyMerge
+//purpose : Compute new connectivity of an element after merging nodes
+// \param [in] elems - the element
+// \param [out] newElemDefs - definition(s) of result element(s)
+// \param [inout] nodeNodeMap - nodes to merge
+// \param [in] avoidMakingHoles - if true and and the element becomes invalid
+// after merging (but not degenerated), removes nodes causing
+// the invalidity from \a nodeNodeMap.
+// \return bool - true if the element should be removed
+//=======================================================================
+
+bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem,
+ vector< ElemFeatures >& newElemDefs,
+ TNodeNodeMap& nodeNodeMap,
+ const bool avoidMakingHoles )
+{
+ bool toRemove = false; // to remove elem
+ int nbResElems = 1; // nb new elements
+
+ newElemDefs.resize(nbResElems);
+ newElemDefs[0].Init( elem );
+ newElemDefs[0].myNodes.clear();
+
+ set<const SMDS_MeshNode*> nodeSet;
+ vector< const SMDS_MeshNode*> curNodes;
+ vector< const SMDS_MeshNode*> & uniqueNodes = newElemDefs[0].myNodes;
+ vector<int> iRepl;
+
+ const int nbNodes = elem->NbNodes();
+ SMDSAbs_EntityType entity = elem->GetEntityType();
+
+ curNodes.resize( nbNodes );
+ uniqueNodes.resize( nbNodes );
+ iRepl.resize( nbNodes );
+ int iUnique = 0, iCur = 0, nbRepl = 0;
+
+ // Get new seq of nodes
+
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
{
- if ( getBox()->IsOut( center, radius ))
- return;
+ const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
- if ( isLeaf() )
- {
- for ( int i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( center, radius ))
- foundElems.insert( _elements[i]->_element );
+ TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
+ if ( nnIt != nodeNodeMap.end() ) {
+ n = (*nnIt).second;
}
+ curNodes[ iCur ] = n;
+ bool isUnique = nodeSet.insert( n ).second;
+ if ( isUnique )
+ uniqueNodes[ iUnique++ ] = n;
else
- {
- for (int i = 0; i < 8; i++)
- ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
- }
+ iRepl[ nbRepl++ ] = iCur;
+ iCur++;
}
- //================================================================================
- /*!
- * \brief Construct the element box
- */
- //================================================================================
+ // Analyse element topology after replacement
- ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
+ int nbUniqueNodes = nodeSet.size();
+ if ( nbNodes != nbUniqueNodes ) // some nodes stick
{
- _element = elem;
- _refCount = 1;
- SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
- while ( nIt->more() )
- Add( SMESH_TNodeXYZ( nIt->next() ));
- Enlarge( tolerance );
- }
+ toRemove = true;
+ nbResElems = 0;
-} // namespace
-
-//=======================================================================
-/*!
- * \brief Implementation of search for the elements by point and
- * of classification of point in 2D mesh
- */
-//=======================================================================
-
-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);
- virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point,
- SMDSAbs_ElementType type );
-
- 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) {}
- };
-};
+ if ( newElemDefs[0].myIsQuad && newElemDefs[0].myType == SMDSAbs_Face && nbNodes > 6 )
+ {
+ // if corner nodes stick, remove medium nodes between them from uniqueNodes
+ int nbCorners = nbNodes / 2;
+ for ( int iCur = 0; iCur < nbCorners; ++iCur )
+ {
+ int iNext = ( iCur + 1 ) % nbCorners;
+ if ( curNodes[ iCur ] == curNodes[ iNext ] ) // corners stick
+ {
+ int iMedium = iCur + nbCorners;
+ vector< const SMDS_MeshNode* >::iterator i =
+ std::find( uniqueNodes.begin() + nbCorners - nbRepl,
+ uniqueNodes.end(),
+ curNodes[ iMedium ]);
+ if ( i != uniqueNodes.end() )
+ {
+ --nbUniqueNodes;
+ for ( ; i+1 != uniqueNodes.end(); ++i )
+ *i = *(i+1);
+ }
+ }
+ }
+ }
-ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
-{
- return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
- << ", _coincides="<<i._coincides << ")";
-}
+ switch ( entity )
+ {
+ case SMDSEntity_Polygon:
+ case SMDSEntity_Quad_Polygon: // Polygon
+ {
+ ElemFeatures* elemType = & newElemDefs[0];
+ const bool isQuad = elemType->myIsQuad;
+ if ( isQuad )
+ SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
+ ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes );
-//=======================================================================
-/*!
- * \brief define tolerance for search
- */
-//=======================================================================
+ // a polygon can divide into several elements
+ vector<const SMDS_MeshNode *> polygons_nodes;
+ vector<int> quantities;
+ nbResElems = SimplifyFace( curNodes, polygons_nodes, quantities );
+ newElemDefs.resize( nbResElems );
+ for ( int inode = 0, iface = 0; iface < nbResElems; iface++ )
+ {
+ ElemFeatures* elemType = & newElemDefs[iface];
+ if ( iface ) elemType->Init( elem );
+
+ vector<const SMDS_MeshNode *>& face_nodes = elemType->myNodes;
+ int nbNewNodes = quantities[iface];
+ face_nodes.assign( polygons_nodes.begin() + inode,
+ polygons_nodes.begin() + inode + nbNewNodes );
+ inode += nbNewNodes;
+ if ( isQuad ) // check if a result elem is a valid quadratic polygon
+ {
+ bool isValid = ( nbNewNodes % 2 == 0 );
+ for ( int i = 0; i < nbNewNodes && isValid; ++i )
+ isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 ));
+ elemType->SetQuad( isValid );
+ if ( isValid ) // put medium nodes after corners
+ SMDS_MeshCell::applyInterlaceRev
+ ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon,
+ nbNewNodes ), face_nodes );
+ }
+ elemType->SetPoly(( nbNewNodes / ( elemType->myIsQuad + 1 ) > 4 ));
+ }
+ nbUniqueNodes = newElemDefs[0].myNodes.size();
+ break;
+ } // Polygon
-double SMESH_ElementSearcherImpl::getTolerance()
-{
- if ( _tolerance < 0 )
- {
- const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
+ case SMDSEntity_Polyhedra: // Polyhedral volume
+ {
+ if ( nbUniqueNodes >= 4 )
+ {
+ // each face has to be analyzed in order to check volume validity
+ if ( const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( elem ))
+ {
+ int nbFaces = aPolyedre->NbFaces();
+
+ vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
+ vector<int> & quantities = newElemDefs[0].myPolyhedQuantities;
+ vector<const SMDS_MeshNode *> faceNodes;
+ poly_nodes.clear();
+ quantities.clear();
+
+ for (int iface = 1; iface <= nbFaces; iface++)
+ {
+ int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+ faceNodes.resize( 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 )
+ {
+ // TODO: remove coincident faces
+ nbResElems = 1;
+ nbUniqueNodes = newElemDefs[0].myNodes.size();
+ }
+ }
+ }
+ }
+ break;
- _tolerance = 0;
- if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
+ // Regular elements
+ // TODO not all the possible cases are solved. Find something more generic?
+ case SMDSEntity_Edge: //////// EDGE
+ case SMDSEntity_Triangle: //// TRIANGLE
+ case SMDSEntity_Quad_Triangle:
+ case SMDSEntity_Tetra:
+ case SMDSEntity_Quad_Tetra: // TETRAHEDRON
{
- double boxSize = _nodeSearcher->getTree()->maxSize();
- _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
+ break;
}
- else if ( _ebbTree && meshInfo.NbElements() > 0 )
+ case SMDSEntity_Quad_Edge:
{
- double boxSize = _ebbTree->maxSize();
- _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
+ break;
}
- if ( _tolerance == 0 )
+ case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE
{
- // 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 ))
+ if ( nbUniqueNodes < 3 )
+ toRemove = true;
+ else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ])
+ toRemove = true; // opposite nodes stick
+ else
+ toRemove = false;
+ break;
+ }
+ case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE
+ {
+ // 1 5 2
+ // +---+---+
+ // | |
+ // 4+ +6
+ // | |
+ // +---+---+
+ // 0 7 3
+ if ( nbUniqueNodes == 6 &&
+ iRepl[0] < 4 &&
+ ( nbRepl == 1 || iRepl[1] >= 4 ))
{
- SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
- elemSize = 1;
- if ( meshInfo.NbNodes() > 2 )
- elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
+ toRemove = false;
}
- else
+ break;
+ }
+ case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE
+ {
+ // 1 5 2
+ // +---+---+
+ // | |
+ // 4+ 8+ +6
+ // | |
+ // +---+---+
+ // 0 7 3
+ if ( nbUniqueNodes == 7 &&
+ iRepl[0] < 4 &&
+ ( nbRepl == 1 || iRepl[1] != 8 ))
{
- SMDS_ElemIteratorPtr elemIt =
- _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
- const SMDS_MeshElement* elem = elemIt->next();
- SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
- SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
- elemSize = 0;
- while ( nodeIt->more() )
+ toRemove = false;
+ }
+ break;
+ }
+ case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON
+ {
+ if ( nbUniqueNodes == 4 ) {
+ // ---------------------------------> tetrahedron
+ if ( curNodes[3] == curNodes[4] &&
+ curNodes[3] == curNodes[5] ) {
+ // top nodes stick
+ toRemove = false;
+ }
+ else if ( curNodes[0] == curNodes[1] &&
+ curNodes[0] == curNodes[2] ) {
+ // bottom nodes stick: set a top before
+ uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
+ uniqueNodes[ 0 ] = curNodes [ 5 ];
+ uniqueNodes[ 1 ] = curNodes [ 4 ];
+ uniqueNodes[ 2 ] = curNodes [ 3 ];
+ toRemove = false;
+ }
+ else if (( curNodes[0] == curNodes[3] ) +
+ ( curNodes[1] == curNodes[4] ) +
+ ( curNodes[2] == curNodes[5] ) == 2 ) {
+ // a lateral face turns into a line
+ toRemove = false;
+ }
+ }
+ else if ( nbUniqueNodes == 5 ) {
+ // PENTAHEDRON --------------------> pyramid
+ if ( curNodes[0] == curNodes[3] )
+ {
+ uniqueNodes[ 0 ] = curNodes[ 1 ];
+ uniqueNodes[ 1 ] = curNodes[ 4 ];
+ uniqueNodes[ 2 ] = curNodes[ 5 ];
+ uniqueNodes[ 3 ] = curNodes[ 2 ];
+ uniqueNodes[ 4 ] = curNodes[ 0 ];
+ toRemove = false;
+ }
+ if ( curNodes[1] == curNodes[4] )
+ {
+ uniqueNodes[ 0 ] = curNodes[ 0 ];
+ uniqueNodes[ 1 ] = curNodes[ 2 ];
+ uniqueNodes[ 2 ] = curNodes[ 5 ];
+ uniqueNodes[ 3 ] = curNodes[ 3 ];
+ uniqueNodes[ 4 ] = curNodes[ 1 ];
+ toRemove = false;
+ }
+ if ( curNodes[2] == curNodes[5] )
{
- double dist = n1.Distance( cast2Node( nodeIt->next() ));
- elemSize = max( dist, elemSize );
+ uniqueNodes[ 0 ] = curNodes[ 0 ];
+ uniqueNodes[ 1 ] = curNodes[ 3 ];
+ uniqueNodes[ 2 ] = curNodes[ 4 ];
+ uniqueNodes[ 3 ] = curNodes[ 1 ];
+ uniqueNodes[ 4 ] = curNodes[ 2 ];
+ toRemove = false;
}
}
- _tolerance = 1e-4 * elemSize;
+ break;
}
- }
- return _tolerance;
-}
+ case SMDSEntity_Hexa:
+ {
+ //////////////////////////////////// HEXAHEDRON
+ SMDS_VolumeTool hexa (elem);
+ hexa.SetExternalNormal();
+ if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
+ //////////////////////// HEX ---> tetrahedron
+ for ( int iFace = 0; iFace < 6; iFace++ ) {
+ const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+ if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
+ // one face turns into a point ...
+ int pickInd = ind[ 0 ];
+ int iOppFace = hexa.GetOppFaceIndex( iFace );
+ ind = hexa.GetFaceNodesIndices( iOppFace );
+ int nbStick = 0;
+ uniqueNodes.clear();
+ for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
+ if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
+ nbStick++;
+ else
+ uniqueNodes.push_back( curNodes[ind[ iCur ]]);
+ }
+ if ( nbStick == 1 ) {
+ // ... and the opposite one - into a triangle.
+ // set a top node
+ uniqueNodes.push_back( curNodes[ pickInd ]);
+ toRemove = false;
+ }
+ break;
+ }
+ }
+ }
+ else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
+ //////////////////////// HEX ---> prism
+ int nbTria = 0, iTria[3];
+ const int *ind; // indices of face nodes
+ // look for triangular faces
+ for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
+ ind = hexa.GetFaceNodesIndices( iFace );
+ TIDSortedNodeSet faceNodes;
+ for ( iCur = 0; iCur < 4; iCur++ )
+ faceNodes.insert( curNodes[ind[iCur]] );
+ if ( faceNodes.size() == 3 )
+ iTria[ nbTria++ ] = iFace;
+ }
+ // check if triangles are opposite
+ if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
+ {
+ // set nodes of the bottom triangle
+ ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
+ vector<int> indB;
+ for ( iCur = 0; iCur < 4; iCur++ )
+ if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
+ indB.push_back( ind[iCur] );
+ if ( !hexa.IsForward() )
+ std::swap( indB[0], indB[2] );
+ for ( iCur = 0; iCur < 3; iCur++ )
+ uniqueNodes[ iCur ] = curNodes[indB[iCur]];
+ // set nodes of the top triangle
+ const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
+ for ( iCur = 0; iCur < 3; ++iCur )
+ for ( int j = 0; j < 4; ++j )
+ if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
+ {
+ uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
+ break;
+ }
+ toRemove = false;
+ break;
+ }
+ }
+ else if (nbUniqueNodes == 5 && nbRepl == 3 ) {
+ //////////////////// HEXAHEDRON ---> pyramid
+ for ( int iFace = 0; iFace < 6; iFace++ ) {
+ const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+ if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
+ curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
+ // one face turns into a point ...
+ int iOppFace = hexa.GetOppFaceIndex( iFace );
+ ind = hexa.GetFaceNodesIndices( iOppFace );
+ uniqueNodes.clear();
+ for ( iCur = 0; iCur < 4; iCur++ ) {
+ if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
+ break;
+ else
+ uniqueNodes.push_back( curNodes[ind[ iCur ]]);
+ }
+ if ( uniqueNodes.size() == 4 ) {
+ // ... and the opposite one is a quadrangle
+ // set a top node
+ const int* indTop = hexa.GetFaceNodesIndices( iFace );
+ uniqueNodes.push_back( curNodes[indTop[ 0 ]]);
+ toRemove = false;
+ }
+ break;
+ }
+ }
+ }
-//================================================================================
-/*!
- * \brief Find intersection of the line and an edge of face and return parameter on line
- */
-//================================================================================
+ if ( toRemove && nbUniqueNodes > 4 ) {
+ ////////////////// HEXAHEDRON ---> polyhedron
+ hexa.SetExternalNormal();
+ vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
+ vector<int> & quantities = newElemDefs[0].myPolyhedQuantities;
+ poly_nodes.reserve( 6 * 4 ); poly_nodes.clear();
+ quantities.reserve( 6 ); quantities.clear();
+ for ( int iFace = 0; iFace < 6; iFace++ )
+ {
+ const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
+ if ( curNodes[ind[0]] == curNodes[ind[2]] ||
+ curNodes[ind[1]] == curNodes[ind[3]] )
+ {
+ quantities.clear();
+ break; // opposite nodes stick
+ }
+ nodeSet.clear();
+ for ( iCur = 0; iCur < 4; iCur++ )
+ {
+ if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second )
+ poly_nodes.push_back( curNodes[ind[ iCur ]]);
+ }
+ if ( nodeSet.size() < 3 )
+ poly_nodes.resize( poly_nodes.size() - nodeSet.size() );
+ else
+ quantities.push_back( nodeSet.size() );
+ }
+ if ( quantities.size() >= 4 )
+ {
+ nbResElems = 1;
+ nbUniqueNodes = poly_nodes.size();
+ newElemDefs[0].SetPoly(true);
+ }
+ }
+ break;
+ } // case HEXAHEDRON
-bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
- const SMDS_MeshElement* face,
- const double tol,
- double & param)
-{
- int nbInts = 0;
- param = 0;
+ default:
+ toRemove = true;
- GeomAPI_ExtremaCurveCurve anExtCC;
- Handle(Geom_Curve) lineCurve = new Geom_Line( line );
+ } // switch ( entity )
- int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
- for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
- {
- GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
- SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
- anExtCC.Init( lineCurve, edge);
- if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
+ if ( toRemove && nbResElems == 0 && avoidMakingHoles )
{
- Quantity_Parameter pl, pe;
- anExtCC.LowerDistanceParameters( pl, pe );
- param += pl;
- if ( ++nbInts == 2 )
- break;
+ // erase from nodeNodeMap nodes whose merge spoils elem
+ vector< const SMDS_MeshNode* > noMergeNodes;
+ SMESH_MeshAlgos::DeMerge( elem, curNodes, noMergeNodes );
+ for ( size_t i = 0; i < noMergeNodes.size(); ++i )
+ nodeNodeMap.erase( noMergeNodes[i] );
}
- }
- if ( nbInts > 0 ) param /= nbInts;
- return nbInts > 0;
-}
-//================================================================================
-/*!
- * \brief Find all faces belonging to the outer boundary of mesh
- */
-//================================================================================
+
+ } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
-void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
-{
- if ( _outerFacesFound ) return;
+ uniqueNodes.resize( nbUniqueNodes );
+
+ if ( !toRemove && nbResElems == 0 )
+ nbResElems = 1;
- // 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.
+ newElemDefs.resize( nbResElems );
- // checked links and links where outer boundary meets internal one
- set< SMESH_TLink > visitedLinks, seamLinks;
+ return !toRemove;
+}
- // 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 );
+// ========================================================
+// class : ComparableElement
+// purpose : allow comparing elements basing on their nodes
+// ========================================================
- TIDSortedElemSet emptySet;
- while ( !startLinks.empty() )
- {
- const SMESH_TLink& link = startLinks.front()._link;
- TIDSortedElemSet& faces = startLinks.front()._faces;
+class ComparableElement : public boost::container::flat_set< smIdType >
+{
+ typedef boost::container::flat_set< smIdType > int_set;
- 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 );
+ const SMDS_MeshElement* myElem;
+ smIdType mySumID;
+ mutable int myGroupID;
- // 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 );
+public:
- // link direction within the outerFace
- gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
- SMESH_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. * M_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 )
+ ComparableElement( const SMDS_MeshElement* theElem ):
+ myElem ( theElem ), mySumID( 0 ), myGroupID( -1 )
+ {
+ this->reserve( theElem->NbNodes() );
+ for ( SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); nodeIt->more(); )
{
- _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 ));
- }
+ smIdType id = nodeIt->next()->GetID();
+ mySumID += id;
+ this->insert( id );
}
- startLinks.pop_front();
}
- _outerFacesFound = true;
- if ( !seamLinks.empty() )
+ const SMDS_MeshElement* GetElem() const { return myElem; }
+
+ int& GroupID() const { return myGroupID; }
+ //int& GroupID() const { return const_cast< int& >( myGroupID ); }
+
+ ComparableElement( const ComparableElement& theSource ) // move copy
+ : int_set()
{
- // 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.
+ ComparableElement& src = const_cast< ComparableElement& >( theSource );
+ (int_set&) (*this ) = std::move( src );
+ myElem = src.myElem;
+ mySumID = src.mySumID;
+ myGroupID = src.myGroupID;
+ }
+ static int HashCode(const ComparableElement& se, int limit )
+ {
+ return ::HashCode( FromSmIdType<int>(se.mySumID), limit );
}
- else
+ static Standard_Boolean IsEqual(const ComparableElement& se1, const ComparableElement& se2 )
{
- _outerFaces.clear();
+ return ( se1 == se2 );
}
-}
+
+};
//=======================================================================
-/*!
- * \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, balls and 0D elements
- */
+//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
//=======================================================================
-int SMESH_ElementSearcherImpl::
-FindElementsByPoint(const gp_Pnt& point,
- SMDSAbs_ElementType type,
- vector< const SMDS_MeshElement* >& foundElements)
+void SMESH_MeshEditor::FindEqualElements( TIDSortedElemSet & theElements,
+ TListOfListOfElementsID & theGroupsOfElementsID )
{
- foundElements.clear();
+ ClearLastCreated();
- double tolerance = getTolerance();
-
- // =================================================================================
- if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball)
- {
- if ( !_nodeSearcher )
- _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
-
- const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
- if ( !closeNode ) return foundElements.size();
+ SMDS_ElemIteratorPtr elemIt;
+ if ( theElements.empty() ) elemIt = GetMeshDS()->elementsIterator();
+ else elemIt = SMESHUtils::elemSetIterator( theElements );
- if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
- return foundElements.size(); // to far from any node
+ typedef NCollection_Map< ComparableElement, ComparableElement > TMapOfElements;
+ typedef std::list<smIdType> TGroupOfElems;
+ TMapOfElements mapOfElements;
+ std::vector< TGroupOfElems > arrayOfGroups;
+ TGroupOfElems groupOfElems;
- if ( type == SMDSAbs_Node )
- {
- foundElements.push_back( closeNode );
- }
- else
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* curElem = elemIt->next();
+ if ( curElem->IsNull() )
+ continue;
+ ComparableElement compElem = curElem;
+ // check uniqueness
+ const ComparableElement& elemInSet = mapOfElements.Added( compElem );
+ if ( elemInSet.GetElem() != curElem ) // coincident elem
{
- SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type );
- while ( elemIt->more() )
- foundElements.push_back( elemIt->next() );
+ int& iG = elemInSet.GroupID();
+ if ( iG < 0 )
+ {
+ iG = arrayOfGroups.size();
+ arrayOfGroups.push_back( groupOfElems );
+ arrayOfGroups[ iG ].push_back( elemInSet.GetElem()->GetID() );
+ }
+ arrayOfGroups[ iG ].push_back( curElem->GetID() );
}
}
- // =================================================================================
- else // elements more complex than 0D
+
+ groupOfElems.clear();
+ std::vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
+ for ( ; groupIt != arrayOfGroups.end(); ++groupIt )
{
- if ( !_ebbTree || _elementType != type )
- {
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
+ if ( groupIt->size() > 1 ) {
+ //groupOfElems.sort(); -- theElements are sorted already
+ theGroupsOfElementsID.emplace_back( *groupIt );
}
- 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 Find an element of given type most close to the given point
- *
- * WARNING: Only face search is implemeneted so far
- */
+//function : MergeElements
+//purpose : In each given group, substitute all elements by the first one.
//=======================================================================
-const SMDS_MeshElement*
-SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point,
- SMDSAbs_ElementType type )
+void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
{
- const SMDS_MeshElement* closestElem = 0;
+ ClearLastCreated();
- if ( type == SMDSAbs_Face )
- {
- if ( !_ebbTree || _elementType != type )
- {
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
- }
- TIDSortedElemSet suspectElems;
- _ebbTree->getElementsNearPoint( point, suspectElems );
+ typedef list<smIdType> TListOfIDs;
+ TListOfIDs rmElemIds; // IDs of elems to remove
- if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
- {
- gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() +
- _ebbTree->getBox()->CornerMax() );
- double radius;
- if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
- radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
- else
- radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
- while ( suspectElems.empty() )
- {
- _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
- radius *= 1.1;
- }
- }
- double minDist = std::numeric_limits<double>::max();
- multimap< double, const SMDS_MeshElement* > dist2face;
- TIDSortedElemSet::iterator elem = suspectElems.begin();
- for ( ; elem != suspectElems.end(); ++elem )
- {
- double dist = SMESH_MeshEditor::GetDistance( dynamic_cast<const SMDS_MeshFace*>(*elem),
- point );
- if ( dist < minDist + 1e-10)
- {
- minDist = dist;
- dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
- }
- }
- if ( !dist2face.empty() )
- {
- multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
- closestElem = d2f->second;
- // if there are several elements at the same distance, select one
- // with GC closest to the point
- typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
- double minDistToGC = 0;
- for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
- {
- if ( minDistToGC == 0 )
- {
- gp_XYZ gc(0,0,0);
- gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
- TXyzIterator(), gc ) / closestElem->NbNodes();
- minDistToGC = point.SquareDistance( gc );
- }
- gp_XYZ gc(0,0,0);
- gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
- TXyzIterator(), gc ) / d2f->second->NbNodes();
- double d = point.SquareDistance( gc );
- if ( d < minDistToGC )
- {
- minDistToGC = d;
- closestElem = d2f->second;
- }
- }
- // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
- // <<closestElem->GetID() << " DIST " << minDist << endl;
+ 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;
}
- else
- {
- // NOT IMPLEMENTED SO FAR
- }
- return closestElem;
-}
+ Remove( rmElemIds, false );
+}
-//================================================================================
-/*!
- * \brief Classify the given point in the closed 2D mesh
- */
-//================================================================================
+//=======================================================================
+//function : MergeEqualElements
+//purpose : Remove all but one of elements built on the same nodes.
+//=======================================================================
-TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
+void SMESH_MeshEditor::MergeEqualElements()
{
- 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_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
+ TIDSortedElemSet aMeshElements; /* empty input ==
+ to merge equal elements in the whole mesh */
+ TListOfListOfElementsID aGroupsOfElementsID;
+ FindEqualElements( aMeshElements, aGroupsOfElementsID );
+ MergeElements( aGroupsOfElementsID );
+}
- int nbInter = u2inters.size();
- if ( nbInter == 0 )
- return TopAbs_OUT;
+//=======================================================================
+//function : findAdjacentFace
+//purpose :
+//=======================================================================
- double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
- if ( nbInter == 1 ) // not closed mesh
- return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
+static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ const SMDS_MeshElement* elem)
+{
+ TIDSortedElemSet elemSet, avoidSet;
+ if ( elem )
+ avoidSet.insert ( elem );
+ return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
+}
- if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
- return TopAbs_ON;
+//=======================================================================
+//function : findSegment
+//purpose : Return a mesh segment by two nodes one of which can be medium
+//=======================================================================
- if ( (f<0) == (l<0) )
- return TopAbs_OUT;
+static const SMDS_MeshElement* findSegment(const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2)
+{
+ SMDS_ElemIteratorPtr it = n1->GetInverseElementIterator( SMDSAbs_Edge );
+ while ( it->more() )
+ {
+ const SMDS_MeshElement* seg = it->next();
+ if ( seg->GetNodeIndex( n2 ) >= 0 )
+ return seg;
+ }
+ return 0;
+}
- int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
- int nbIntAfterPoint = nbInter - nbIntBeforePoint;
- if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
- return TopAbs_IN;
+//=======================================================================
+//function : FindFreeBorder
+//purpose :
+//=======================================================================
- nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
+#define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
- 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.
+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;
+ // find border face between theFirstNode and theSecondNode
+ const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
+ if ( !curElem )
+ return false;
- 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 ];
+ theFaces.push_back( curElem );
+ theNodes.push_back( theFirstNode );
+ theNodes.push_back( theSecondNode );
- gp_Ax1 lineAxis( point, axisDir[axis]);
- gp_Lin line ( lineAxis );
+ const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
+ //TIDSortedElemSet foundElems;
+ bool needTheLast = ( theLastNode != 0 );
- // 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();
+ vector<const SMDS_MeshNode*> nodes;
+
+ while ( nStart != theLastNode ) {
+ if ( nStart == theFirstNode )
+ return !needTheLast;
- // Count intersections before and after the point excluding touching ones.
- // If hasPositionInfo we count intersections of outer boundary only
+ // find all free border faces sharing nStart
- 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() )
+ list< const SMDS_MeshElement* > curElemList;
+ list< const SMDS_MeshNode* > nStartList;
+ SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
+ while ( invElemIt->more() ) {
+ const SMDS_MeshElement* e = invElemIt->next();
+ //if ( e == curElem || foundElems.insert( e ).second ) // e can encounter twice in border
{
- 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;
- }
+ // get nodes
+ nodes.assign( SMDS_MeshElement::iterator( e->interlacedNodesIterator() ),
+ SMDS_MeshElement::iterator() );
+ nodes.push_back( nodes[ 0 ]);
- // skip tangent intersections
- int nbTgt = 0;
- const SMDS_MeshElement* prevFace = u_int1->second._face;
- while ( ok && u_int2->second._coincides )
+ // check 2 links
+ int iNode = 0, nbNodes = nodes.size() - 1;
+ for ( iNode = 0; iNode < nbNodes; iNode++ )
+ if ((( nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
+ ( nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
+ ( ControlFreeBorder( &nodes[ iNode ], e->GetID() )))
{
- if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
- ok = false;
- else
- {
- nbTgt++;
- u_int2++;
- ok = ( u_int2 != u2inters.end() );
- }
+ nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart )]);
+ curElemList.push_back( e );
}
- if ( !ok ) break;
+ }
+ }
+ // analyse the found
- // 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 );
+ int nbNewBorders = curElemList.size();
+ if ( nbNewBorders == 0 ) {
+ // no free border furthermore
+ return !needTheLast;
+ }
+ else if ( nbNewBorders == 1 ) {
+ // one more element found
+ nIgnore = nStart;
+ nStart = nStartList.front();
+ curElem = curElemList.front();
+ theFaces.push_back( curElem );
+ theNodes.push_back( nStart );
+ }
+ else {
+ // several continuations found
+ list< const SMDS_MeshElement* >::iterator curElemIt;
+ list< const SMDS_MeshNode* >::iterator nStartIt;
+ // check if one of them reached the last node
+ if ( needTheLast ) {
+ for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
+ curElemIt!= curElemList.end();
+ curElemIt++, nStartIt++ )
+ if ( *nStartIt == theLastNode ) {
+ theFaces.push_back( *curElemIt );
+ theNodes.push_back( *nStartIt );
+ return true;
}
+ }
+ // find the best free border by the continuations
+ list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
+ list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
+ for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
+ curElemIt!= curElemList.end();
+ curElemIt++, nStartIt++ )
+ {
+ cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
+ cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
+ // find one more free border
+ if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
+ cNL->clear();
+ cFL->clear();
}
- 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;
+ else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
+ // choice: clear a worse one
+ int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
+ int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
+ contNodes[ iWorse ].clear();
+ contFaces[ iWorse ].clear();
}
-
- 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 ( contNodes[0].empty() && contNodes[1].empty() )
+ return false;
- 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 );
- }
+ // push_back the best free border
+ cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
+ cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
+ //theNodes.pop_back(); // remove nIgnore
+ theNodes.pop_back(); // remove nStart
+ //theFaces.pop_back(); // remove curElem
+ theNodes.splice( theNodes.end(), *cNL );
+ theFaces.splice( theFaces.end(), *cFL );
+ return true;
- } // two attempts - with and w/o faces position info in the mesh
+ } // several continuations found
+ } // while ( nStart != theLastNode )
- return TopAbs_UNKNOWN;
+ return true;
}
//=======================================================================
-/*!
- * \brief Return elements possibly intersecting the line
- */
+//function : CheckFreeBorderNodes
+//purpose : Return true if the tree nodes are on a free border
//=======================================================================
-void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
- SMDSAbs_ElementType type,
- vector< const SMDS_MeshElement* >& foundElems)
+bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
+ const SMDS_MeshNode* theNode2,
+ const SMDS_MeshNode* theNode3)
{
- 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());
+ list< const SMDS_MeshNode* > nodes;
+ list< const SMDS_MeshElement* > faces;
+ return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
}
//=======================================================================
-/*!
- * \brief Return SMESH_ElementSearcher
- */
+//function : SewFreeBorder
+//purpose :
+//warning : for border-to-side sewing theSideSecondNode is considered as
+// the last side node and theSideThirdNode is not used
//=======================================================================
-SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
+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)
{
- return new SMESH_ElementSearcherImpl( *GetMeshDS() );
-}
+ ClearLastCreated();
-//=======================================================================
-/*!
- * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
- */
-//=======================================================================
+ Sew_Error aResult = SEW_OK;
-SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
-{
- return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
-}
+ // ====================================
+ // find side nodes and elements
+ // ====================================
-//=======================================================================
-/*!
- * \brief Return true if the point is IN or ON of the element
- */
-//=======================================================================
+ list< const SMDS_MeshNode* > nSide[ 2 ];
+ list< const SMDS_MeshElement* > eSide[ 2 ];
+ list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
+ list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
-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 );
+ // Free border 1
+ // --------------
+ 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,
+ nSide[1], eSide[1])) {
+ MESSAGE(" Free Border 2 not found " );
+ aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
+ }
}
+ if ( aResult != SEW_OK )
+ return aResult;
- // get ordered nodes
+ if (!theSideIsFreeBorder) {
+ // Side 2
+ // --------------
- vector< gp_XYZ > xyz;
- vector<const SMDS_MeshNode*> nodeList;
+ // -------------------------------------------------------------------------
+ // Algo:
+ // 1. If nodes to merge are not coincident, move nodes of the free border
+ // from the coord sys defined by the direction from the first to last
+ // nodes of the border to the correspondent sys of the side 2
+ // 2. On the side 2, find the links most co-directed with the correspondent
+ // links of the free border
+ // -------------------------------------------------------------------------
- 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( SMESH_TNodeXYZ(node) );
- nodeList.push_back(node);
- }
+ // 1. Since sewing may break if there are volumes to split on the side 2,
+ // we won't move nodes but just compute new coordinates for them
+ typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
+ TNodeXYZMap nBordXYZ;
+ list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
+ list< const SMDS_MeshNode* >::iterator nBordIt;
- int i, nbNodes = element->NbNodes();
+ gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
+ gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
+ gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
+ gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
+ double tol2 = 1.e-8;
+ gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
+ if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
+ // Need node movement.
- 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;
+ // find X and Z axes to create trsf
+ gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
+ gp_Vec X = Zs ^ Zb;
+ if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
+ // Zb || Zs
+ X = gp_Ax2( gp::Origin(), Zb ).XDirection();
+
+ // coord systems
+ gp_Ax3 toBordAx( Pb1, Zb, X );
+ gp_Ax3 fromSideAx( Ps1, Zs, X );
+ gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
+ // set trsf
+ gp_Trsf toBordSys, fromSide2Sys;
+ toBordSys.SetTransformation( toBordAx );
+ fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
+ fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
+
+ // move
+ for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
+ const SMDS_MeshNode* n = *nBordIt;
+ gp_XYZ xyz( n->X(),n->Y(),n->Z() );
+ toBordSys.Transforms( xyz );
+ fromSide2Sys.Transforms( xyz );
+ nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
}
- 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;
- }
+ else {
+ // just insert nodes XYZ in the nBordXYZ map
+ for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
+ const SMDS_MeshNode* n = *nBordIt;
+ nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
}
}
- 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;
+ // 2. On the side 2, find the links most co-directed with the correspondent
+ // links of the free border
- // 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;
-}
-
-//=======================================================================
-
-namespace
-{
- // Position of a point relative to a segment
- // . .
- // . LEFT .
- // . .
- // VERTEX 1 o----ON-----> VERTEX 2
- // . .
- // . RIGHT .
- // . .
- enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
- POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
- struct PointPos
- {
- PositionName _name;
- int _index; // index of vertex or segment
-
- PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
- bool operator < (const PointPos& other ) const
- {
- if ( _name == other._name )
- return ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
- return _name < other._name;
- }
- };
-
- //================================================================================
- /*!
- * \brief Return of a point relative to a segment
- * \param point2D - the point to analyze position of
- * \param xyVec - end points of segments
- * \param index0 - 0-based index of the first point of segment
- * \param posToFindOut - flags of positions to detect
- * \retval PointPos - point position
- */
- //================================================================================
-
- PointPos getPointPosition( const gp_XY& point2D,
- const gp_XY* segEnds,
- const int index0 = 0,
- const int posToFindOut = POS_ALL)
- {
- const gp_XY& p1 = segEnds[ index0 ];
- const gp_XY& p2 = segEnds[ index0+1 ];
- const gp_XY grad = p2 - p1;
-
- if ( posToFindOut & POS_VERTEX )
- {
- // check if the point2D is at "vertex 1" zone
- gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
- p1.Y() + grad.X() ) };
- if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
- return PointPos( POS_VERTEX, index0 );
-
- // check if the point2D is at "vertex 2" zone
- gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
- p2.Y() + grad.X() ) };
- if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
- return PointPos( POS_VERTEX, index0 + 1);
- }
- double edgeEquation =
- ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
- return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
- }
-}
-
-//=======================================================================
-/*!
- * \brief Return minimal distance from a point to a face
- *
- * Currently we ignore non-planarity and 2nd order of face
- */
-//=======================================================================
-
-double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face,
- const gp_Pnt& point )
-{
- double badDistance = -1;
- if ( !face ) return badDistance;
-
- // coordinates of nodes (medium nodes, if any, ignored)
- typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
- vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
- xyz.resize( face->NbCornerNodes()+1 );
-
- // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
- // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
- gp_Trsf trsf;
- gp_Vec OZ ( xyz[0], xyz[1] );
- gp_Vec OX ( xyz[0], xyz[2] );
- if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
- {
- if ( xyz.size() < 4 ) return badDistance;
- OZ = gp_Vec ( xyz[0], xyz[2] );
- OX = gp_Vec ( xyz[0], xyz[3] );
- }
- gp_Ax3 tgtCS;
- try {
- tgtCS = gp_Ax3( xyz[0], OZ, OX );
- }
- catch ( Standard_Failure ) {
- return badDistance;
- }
- trsf.SetTransformation( tgtCS );
-
- // move all the nodes to 2D
- vector<gp_XY> xy( xyz.size() );
- for ( size_t i = 0;i < xyz.size()-1; ++i )
- {
- gp_XYZ p3d = xyz[i];
- trsf.Transforms( p3d );
- xy[i].SetCoord( p3d.X(), p3d.Z() );
- }
- xyz.back() = xyz.front();
- xy.back() = xy.front();
-
- // // move the point in 2D
- gp_XYZ tmpPnt = point.XYZ();
- trsf.Transforms( tmpPnt );
- gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
-
- // loop on segments of the face to analyze point position ralative to the face
- set< PointPos > pntPosSet;
- for ( size_t i = 1; i < xy.size(); ++i )
- {
- PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
- pntPosSet.insert( pos );
- }
-
- // compute distance
- PointPos pos = *pntPosSet.begin();
- // cout << "Face " << face->GetID() << " DIST: ";
- switch ( pos._name )
- {
- case POS_LEFT: {
- // point is most close to a segment
- gp_Vec p0p1( point, xyz[ pos._index ] );
- gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
- p1p2.Normalize();
- double projDist = p0p1 * p1p2; // distance projected to the segment
- gp_Vec projVec = p1p2 * projDist;
- gp_Vec distVec = p0p1 - projVec;
- // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID()
- // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
- return distVec.Magnitude();
- }
- case POS_RIGHT: {
- // point is inside the face
- double distToFacePlane = tmpPnt.Y();
- // cout << distToFacePlane << ", INSIDE " << endl;
- return Abs( distToFacePlane );
- }
- case POS_VERTEX: {
- // point is most close to a node
- gp_Vec distVec( point, xyz[ pos._index ]);
- // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
- return distVec.Magnitude();
- }
- }
- return badDistance;
-}
-
-//=======================================================================
-//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 );
- // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
- // after MergeNodes() w/o creating node in place of merged ones.
- const SMDS_PositionPtr& pos = nToRemove->GetPosition();
- if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
- if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
- sm->SetIsAlwaysComputed( true );
- }
-
- 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
- }
- curNodes[ iCur ] = n;
- bool isUnique = nodeSet.insert( n ).second;
- if ( isUnique )
- uniqueNodes[ iUnique++ ] = n;
- else
- iRepl[ nbRepl++ ] = iCur;
- 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;
- } // poly element
-
- // 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
- if ( nbUniqueNodes == 4 ) {
- // ---------------------------------> tetrahedron
- if (nbRepl == 3 &&
- iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
- // all top nodes stick: reverse a bottom
- uniqueNodes[ 0 ] = curNodes [ 1 ];
- uniqueNodes[ 1 ] = curNodes [ 0 ];
- }
- else if (nbRepl == 3 &&
- iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
- // all bottom nodes stick: set a top before
- uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
- uniqueNodes[ 0 ] = curNodes [ 3 ];
- uniqueNodes[ 1 ] = curNodes [ 4 ];
- uniqueNodes[ 2 ] = curNodes [ 5 ];
- }
- else if (nbRepl == 4 &&
- iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
- // a lateral face turns into a line: reverse a bottom
- uniqueNodes[ 0 ] = curNodes [ 1 ];
- uniqueNodes[ 1 ] = curNodes [ 0 ];
- }
- else
- isOk = false;
- }
- else if ( nbUniqueNodes == 5 ) {
- // PENTAHEDRON --------------------> 2 tetrahedrons
- if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
- // a bottom node sticks with a linked top one
- // 1.
- SMDS_MeshElement* newElem =
- aMesh->AddVolume(curNodes[ 3 ],
- curNodes[ 4 ],
- curNodes[ 5 ],
- curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- // 2. : reverse a bottom
- uniqueNodes[ 0 ] = curNodes [ 1 ];
- uniqueNodes[ 1 ] = curNodes [ 0 ];
- nbUniqueNodes = 4;
- }
- else
- isOk = false;
- }
- else
- isOk = false;
- break;
- case 8: {
- if(elem->IsQuadratic()) { // Quadratic quadrangle
- // 1 5 2
- // +---+---+
- // | |
- // | |
- // 4+ +6
- // | |
- // | |
- // +---+---+
- // 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];
- uniqueNodes[1] = curNodes[2];
- uniqueNodes[2] = curNodes[3];
- uniqueNodes[3] = curNodes[5];
- uniqueNodes[4] = curNodes[6];
- uniqueNodes[5] = curNodes[7];
- isOk = true;
- }
- if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
- uniqueNodes[0] = curNodes[0];
- uniqueNodes[1] = curNodes[1];
- uniqueNodes[2] = curNodes[2];
- uniqueNodes[3] = curNodes[4];
- uniqueNodes[4] = curNodes[5];
- uniqueNodes[5] = curNodes[6];
- isOk = true;
- }
- if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
- uniqueNodes[0] = curNodes[1];
- uniqueNodes[1] = curNodes[2];
- uniqueNodes[2] = curNodes[3];
- uniqueNodes[3] = curNodes[5];
- uniqueNodes[4] = curNodes[6];
- uniqueNodes[5] = curNodes[0];
- isOk = true;
- }
- if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
- uniqueNodes[0] = curNodes[0];
- uniqueNodes[1] = curNodes[1];
- uniqueNodes[2] = curNodes[3];
- uniqueNodes[3] = curNodes[4];
- uniqueNodes[4] = curNodes[6];
- uniqueNodes[5] = curNodes[7];
- isOk = true;
- }
- if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
- uniqueNodes[0] = curNodes[0];
- uniqueNodes[1] = curNodes[2];
- uniqueNodes[2] = curNodes[3];
- uniqueNodes[3] = curNodes[1];
- uniqueNodes[4] = curNodes[6];
- uniqueNodes[5] = curNodes[7];
- isOk = true;
- }
- if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
- uniqueNodes[0] = curNodes[0];
- uniqueNodes[1] = curNodes[1];
- uniqueNodes[2] = curNodes[2];
- uniqueNodes[3] = curNodes[4];
- uniqueNodes[4] = curNodes[5];
- uniqueNodes[5] = curNodes[7];
- isOk = true;
- }
- if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
- uniqueNodes[0] = curNodes[0];
- uniqueNodes[1] = curNodes[1];
- uniqueNodes[2] = curNodes[3];
- uniqueNodes[3] = curNodes[4];
- uniqueNodes[4] = curNodes[2];
- uniqueNodes[5] = curNodes[7];
- isOk = true;
- }
- if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
- uniqueNodes[0] = curNodes[0];
- uniqueNodes[1] = curNodes[1];
- uniqueNodes[2] = curNodes[2];
- uniqueNodes[3] = curNodes[4];
- uniqueNodes[4] = curNodes[5];
- uniqueNodes[5] = curNodes[3];
- 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
- isOk = false;
- SMDS_VolumeTool hexa (elem);
- hexa.SetExternalNormal();
- if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
- //////////////////////// HEX ---> 1 tetrahedron
- for ( int iFace = 0; iFace < 6; iFace++ ) {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
- // one face turns into a point ...
- int iOppFace = hexa.GetOppFaceIndex( iFace );
- ind = hexa.GetFaceNodesIndices( iOppFace );
- int nbStick = 0;
- for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
- if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
- nbStick++;
- }
- if ( nbStick == 1 ) {
- // ... and the opposite one - into a triangle.
- // set a top node
- ind = hexa.GetFaceNodesIndices( iFace );
- uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
- isOk = true;
- }
- break;
- }
- }
- }
- else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
- //////////////////////// HEX ---> 1 prism
- int nbTria = 0, iTria[3];
- const int *ind; // indices of face nodes
- // look for triangular faces
- for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
- ind = hexa.GetFaceNodesIndices( iFace );
- TIDSortedNodeSet faceNodes;
- for ( iCur = 0; iCur < 4; iCur++ )
- faceNodes.insert( curNodes[ind[iCur]] );
- if ( faceNodes.size() == 3 )
- iTria[ nbTria++ ] = iFace;
- }
- // check if triangles are opposite
- if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
- {
- isOk = true;
- // set nodes of the bottom triangle
- ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
- vector<int> indB;
- for ( iCur = 0; iCur < 4; iCur++ )
- if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
- indB.push_back( ind[iCur] );
- if ( !hexa.IsForward() )
- std::swap( indB[0], indB[2] );
- for ( iCur = 0; iCur < 3; iCur++ )
- uniqueNodes[ iCur ] = curNodes[indB[iCur]];
- // set nodes of the top triangle
- const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
- for ( iCur = 0; iCur < 3; ++iCur )
- for ( int j = 0; j < 4; ++j )
- if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
- {
- uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
- break;
- }
- }
- break;
- }
- else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
- //////////////////// HEXAHEDRON ---> 2 tetrahedrons
- for ( int iFace = 0; iFace < 6; iFace++ ) {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
- // one face turns into a point ...
- int iOppFace = hexa.GetOppFaceIndex( iFace );
- ind = hexa.GetFaceNodesIndices( iOppFace );
- int nbStick = 0;
- iUnique = 2; // reverse a tetrahedron 1 bottom
- for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
- if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
- nbStick++;
- else if ( iUnique >= 0 )
- uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
- }
- if ( nbStick == 0 ) {
- // ... and the opposite one is a quadrangle
- // set a top node
- const int* indTop = hexa.GetFaceNodesIndices( iFace );
- uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
- nbUniqueNodes = 4;
- // tetrahedron 2
- SMDS_MeshElement* newElem =
- aMesh->AddVolume(curNodes[ind[ 0 ]],
- curNodes[ind[ 3 ]],
- curNodes[ind[ 2 ]],
- curNodes[indTop[ 0 ]]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- isOk = true;
- }
- break;
- }
- }
- }
- else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
- ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
- // find indices of quad and tri faces
- int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
- for ( iFace = 0; iFace < 6; iFace++ ) {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- nodeSet.clear();
- for ( iCur = 0; iCur < 4; iCur++ )
- nodeSet.insert( curNodes[ind[ iCur ]] );
- nbUniqueNodes = nodeSet.size();
- if ( nbUniqueNodes == 3 )
- iTriFace[ nbTri++ ] = iFace;
- else if ( nbUniqueNodes == 4 )
- iQuadFace[ nbQuad++ ] = iFace;
- }
- if (nbQuad == 2 && nbTri == 4 &&
- hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
- // 2 opposite quadrangles stuck with a diagonal;
- // sample groups of merged indices: (0-4)(2-6)
- // --------------------------------------------> 2 tetrahedrons
- const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
- const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
- int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
- if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
- curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
- // stuck with 0-2 diagonal
- i0 = ind1[ 3 ];
- i1d = ind1[ 0 ];
- i2 = ind1[ 1 ];
- i3d = ind1[ 2 ];
- i0t = ind2[ 1 ];
- i2t = ind2[ 3 ];
- }
- else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
- curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
- // stuck with 1-3 diagonal
- i0 = ind1[ 0 ];
- i1d = ind1[ 1 ];
- i2 = ind1[ 2 ];
- i3d = ind1[ 3 ];
- i0t = ind2[ 0 ];
- i2t = ind2[ 1 ];
- }
- else {
- ASSERT(0);
- }
- // tetrahedron 1
- uniqueNodes[ 0 ] = curNodes [ i0 ];
- uniqueNodes[ 1 ] = curNodes [ i1d ];
- uniqueNodes[ 2 ] = curNodes [ i3d ];
- uniqueNodes[ 3 ] = curNodes [ i0t ];
- nbUniqueNodes = 4;
- // tetrahedron 2
- SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
- curNodes[ i2 ],
- curNodes[ i3d ],
- curNodes[ i2t ]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- isOk = true;
- }
- else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
- ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
- // --------------------------------------------> prism
- // find 2 opposite triangles
- nbUniqueNodes = 6;
- for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
- if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
- // find indices of kept and replaced nodes
- // and fill unique nodes of 2 opposite triangles
- const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
- const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
- const SMDS_MeshNode** hexanodes = hexa.GetNodes();
- // fill unique nodes
- iUnique = 0;
- isOk = true;
- for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
- const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
- const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
- if ( n == nInit ) {
- // iCur of a linked node of the opposite face (make normals co-directed):
- int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
- // check that correspondent corners of triangles are linked
- if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
- isOk = false;
- else {
- uniqueNodes[ iUnique ] = n;
- uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
- iUnique++;
- }
- }
- }
- break;
- }
- }
- }
- } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
- else
- {
- MESSAGE("MergeNodes() removes hexahedron "<< elem);
- }
- break;
- } // HEXAHEDRON
-
- default:
- isOk = false;
- } // switch ( nbNodes )
-
- } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
-
- if ( isOk ) { // the elem remains valid after sticking nodes
- if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
- {
- // Change nodes of polyedre
- 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 (nbFaces);
-
- for (int iface = 1; iface <= nbFaces; iface++) {
- int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
- quantities[iface - 1] = nbFaceNodes;
-
- for (inode = 1; inode <= nbFaceNodes; inode++) {
- const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
-
- TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
- if (nnIt != nodeNodeMap.end()) { // curNode sticks
- curNode = (*nnIt).second;
- }
- poly_nodes.push_back(curNode);
- }
- }
- aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
- }
- }
- else // replace non-polyhedron elements
- {
- const SMDSAbs_ElementType etyp = elem->GetType();
- const int elemId = elem->GetID();
- const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
- uniqueNodes.resize(nbUniqueNodes);
-
- SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
-
- aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
- SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
- if ( sm && newElem )
- sm->AddElement( newElem );
- if ( elem != newElem )
- ReplaceElemInGroups( elem, newElem, aMesh );
- }
- }
- else {
- // Remove invalid regular element or invalid polygon
- rmElemIds.push_back( elem->GetID() );
- }
-
- } // loop on elements
-
- // Remove bad elements, then equal nodes (order important)
-
- Remove( rmElemIds, false );
- Remove( rmNodeIds, true );
-
-}
-
-
-// ========================================================
-// class : SortableElement
-// purpose : allow sorting elements basing on their nodes
-// ========================================================
-class SortableElement : public set <const SMDS_MeshElement*>
-{
-public:
-
- SortableElement( const SMDS_MeshElement* theElem )
- {
- myElem = theElem;
- SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
- while ( nodeIt->more() )
- this->insert( nodeIt->next() );
- }
-
- const SMDS_MeshElement* Get() const
- { return myElem; }
-
- void Set(const SMDS_MeshElement* e) const
- { myElem = e; }
-
-
-private:
- mutable const SMDS_MeshElement* myElem;
-};
-
-//=======================================================================
-//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::FindEqualElements(TIDSortedElemSet & theElements,
- TListOfListOfElementsID & theGroupsOfElementsID)
-{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- typedef map< SortableElement, int > TMapOfNodeSet;
- typedef list<int> TGroupOfElems;
-
- if ( theElements.empty() )
- { // get all elements in the mesh
- SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
- while ( eIt->more() )
- theElements.insert( theElements.end(), eIt->next());
- }
-
- vector< TGroupOfElems > arrayOfGroups;
- TGroupOfElems groupOfElems;
- TMapOfNodeSet mapOfNodeSet;
-
- TIDSortedElemSet::iterator elemIt = theElements.begin();
- for ( int i = 0, j=0; elemIt != theElements.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++;
- }
- }
-
- vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
- for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
- groupOfElems = *groupIt;
- if ( groupOfElems.size() > 1 ) {
- groupOfElems.sort();
- theGroupsOfElementsID.push_back(groupOfElems);
- }
- }
-}
-
-//=======================================================================
-//function : MergeElements
-//purpose : In each given group, substitute all elements by the first one.
-//=======================================================================
-
-void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
-{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- typedef list<int> TListOfIDs;
- TListOfIDs rmElemIds; // IDs of elems to remove
-
- 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()
-{
- TIDSortedElemSet 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 TIDSortedElemSet& elemSet,
- const TIDSortedElemSet& avoidSet,
- int* n1ind,
- int* n2ind)
-
-{
- 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 (avoidSet.count( elem ))
- continue;
- if ( !elemSet.empty() && !elemSet.count( elem ))
- continue;
- // index of n1
- i1 = elem->GetNodeIndex( n1 );
- // find a n2 linked to n1
- 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;
- }
- }
- }
- if ( n1ind ) *n1ind = i1;
- if ( n2ind ) *n2ind = i2;
- return face;
-}
-
-//=======================================================================
-//function : findAdjacentFace
-//purpose :
-//=======================================================================
-
-static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
- const SMDS_MeshNode* n2,
- const SMDS_MeshElement* elem)
-{
- TIDSortedElemSet elemSet, avoidSet;
- if ( elem )
- avoidSet.insert ( elem );
- return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
-}
-
-//=======================================================================
-//function : FindFreeBorder
-//purpose :
-//=======================================================================
-
-#define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
-
-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;
- // find border face between theFirstNode and theSecondNode
- const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
- if ( !curElem )
- return false;
-
- theFaces.push_back( curElem );
- theNodes.push_back( theFirstNode );
- theNodes.push_back( theSecondNode );
-
- //vector<const SMDS_MeshNode*> nodes;
- const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
- TIDSortedElemSet foundElems;
- bool needTheLast = ( theLastNode != 0 );
-
- while ( nStart != theLastNode ) {
- if ( nStart == theFirstNode )
- return !needTheLast;
-
- // find all free border faces sharing form nStart
-
- list< const SMDS_MeshElement* > curElemList;
- list< const SMDS_MeshNode* > nStartList;
- 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];
- vector<const SMDS_MeshNode*> nodes(nbNodes+1);
-
- if(e->IsQuadratic()) {
- 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_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
- while( anIter->more() ) {
- nodes[ iNode++ ] = cast2Node(anIter->next());
- }
- }
- else {
- SMDS_ElemIteratorPtr nIt = e->nodesIterator();
- while ( nIt->more() )
- nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
- }
- nodes[ iNode ] = nodes[ 0 ];
- // check 2 links
- for ( iNode = 0; iNode < nbNodes; iNode++ )
- if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
- (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
- ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
- {
- nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
- curElemList.push_back( e );
- }
- }
- }
- // analyse the found
-
- int nbNewBorders = curElemList.size();
- if ( nbNewBorders == 0 ) {
- // no free border furthermore
- return !needTheLast;
- }
- else if ( nbNewBorders == 1 ) {
- // one more element found
- nIgnore = nStart;
- nStart = nStartList.front();
- curElem = curElemList.front();
- theFaces.push_back( curElem );
- theNodes.push_back( nStart );
- }
- else {
- // several continuations found
- list< const SMDS_MeshElement* >::iterator curElemIt;
- list< const SMDS_MeshNode* >::iterator nStartIt;
- // check if one of them reached the last node
- if ( needTheLast ) {
- for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
- curElemIt!= curElemList.end();
- curElemIt++, nStartIt++ )
- if ( *nStartIt == theLastNode ) {
- theFaces.push_back( *curElemIt );
- theNodes.push_back( *nStartIt );
- return true;
- }
- }
- // find the best free border by the continuations
- list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
- list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
- for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
- curElemIt!= curElemList.end();
- curElemIt++, nStartIt++ )
- {
- cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
- cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
- // find one more free border
- if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
- cNL->clear();
- cFL->clear();
- }
- else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
- // choice: clear a worse one
- int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
- int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
- contNodes[ iWorse ].clear();
- contFaces[ iWorse ].clear();
- }
- }
- if ( contNodes[0].empty() && contNodes[1].empty() )
- return false;
-
- // append the best free border
- cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
- cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
- theNodes.pop_back(); // remove nIgnore
- theNodes.pop_back(); // remove nStart
- theFaces.pop_back(); // remove curElem
- list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
- list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
- for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
- for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
- return true;
-
- } // several continuations found
- } // while ( nStart != theLastNode )
-
- return true;
-}
-
-//=======================================================================
-//function : CheckFreeBorderNodes
-//purpose : Return true if the tree nodes are on a free border
-//=======================================================================
-
-bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
- const SMDS_MeshNode* theNode2,
- const SMDS_MeshNode* theNode3)
-{
- list< const SMDS_MeshNode* > nodes;
- list< const SMDS_MeshElement* > faces;
- return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
-}
-
-//=======================================================================
-//function : SewFreeBorder
-//purpose :
-//=======================================================================
-
-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)
-{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- MESSAGE("::SewFreeBorder()");
- Sew_Error aResult = SEW_OK;
-
- // ====================================
- // find side nodes and elements
- // ====================================
-
- list< const SMDS_MeshNode* > nSide[ 2 ];
- list< const SMDS_MeshElement* > eSide[ 2 ];
- list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
- list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
-
- // Free border 1
- // --------------
- 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,
- nSide[1], eSide[1])) {
- MESSAGE(" Free Border 2 not found " );
- aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
- }
- }
- if ( aResult != SEW_OK )
- return aResult;
-
- if (!theSideIsFreeBorder) {
- // Side 2
- // --------------
-
- // -------------------------------------------------------------------------
- // Algo:
- // 1. If nodes to merge are not coincident, move nodes of the free border
- // from the coord sys defined by the direction from the first to last
- // nodes of the border to the correspondent sys of the side 2
- // 2. On the side 2, find the links most co-directed with the correspondent
- // links of the free border
- // -------------------------------------------------------------------------
-
- // 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;
- list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
- list< const SMDS_MeshNode* >::iterator nBordIt;
-
- gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
- gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
- gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
- gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
- double tol2 = 1.e-8;
- gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
- if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
- // Need node movement.
-
- // find X and Z axes to create trsf
- gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
- gp_Vec X = Zs ^ Zb;
- if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
- // Zb || Zs
- X = gp_Ax2( gp::Origin(), Zb ).XDirection();
-
- // coord systems
- gp_Ax3 toBordAx( Pb1, Zb, X );
- gp_Ax3 fromSideAx( Ps1, Zs, X );
- gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
- // set trsf
- gp_Trsf toBordSys, fromSide2Sys;
- toBordSys.SetTransformation( toBordAx );
- fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
- fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
-
- // move
- for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
- const SMDS_MeshNode* n = *nBordIt;
- gp_XYZ xyz( n->X(),n->Y(),n->Z() );
- toBordSys.Transforms( xyz );
- fromSide2Sys.Transforms( xyz );
- nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
- }
- }
- else {
- // just insert nodes XYZ in the nBordXYZ map
- for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
- const SMDS_MeshNode* n = *nBordIt;
- nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
- }
- }
-
- // 2. On the side 2, find the links most co-directed with the correspondent
- // links of the free border
-
- list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
- list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
- sideNodes.push_back( theSideFirstNode );
+ list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
+ list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
+ sideNodes.push_back( theSideFirstNode );
bool hasVolumes = false;
LinkID_Gen aLinkID_Gen( GetMeshDS() );
//const SMDS_MeshNode* faceNodes[ 4 ];
const SMDS_MeshNode* sideNode;
- const SMDS_MeshElement* sideElem;
+ const SMDS_MeshElement* sideElem = 0;
const SMDS_MeshNode* prevSideNode = theSideFirstNode;
const SMDS_MeshNode* prevBordNode = theBordFirstNode;
nBordIt = bordNodes.begin();
{
const SMDS_MeshElement* elem = invElemIt->next();
// prepare data for a loop on links coming to prevSideNode, of a face or a volume
- int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
+ int iPrevNode = 0, iNode = 0, nbNodes = elem->NbNodes();
vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
bool isVolume = volume.Set( elem );
const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
if ( isVolume ) // --volume
hasVolumes = true;
- else if ( elem->GetType()==SMDSAbs_Face ) { // --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_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();
- while( anIter->more() ) {
- nodes[ iNode ] = cast2Node(anIter->next());
- if ( nodes[ iNode++ ] == prevSideNode )
- iPrevNode = iNode - 1;
- }
- }
- else {
- SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
- while ( nIt->more() ) {
- nodes[ iNode ] = cast2Node( nIt->next() );
- if ( nodes[ iNode++ ] == prevSideNode )
- iPrevNode = iNode - 1;
- }
+ SMDS_NodeIteratorPtr nIt = elem->interlacedNodesIterator();
+ while ( nIt->more() ) {
+ nodes[ iNode ] = cast2Node( nIt->next() );
+ if ( nodes[ iNode++ ] == prevSideNode )
+ iPrevNode = iNode - 1;
}
// there are 2 links to check
nbNodes = 2;
} // loop on inverse elements of prevSideNode
if ( !sideNode ) {
- MESSAGE(" Cant find path by links of the Side 2 ");
+ MESSAGE(" Can't find path by links of the Side 2 ");
return SEW_BAD_SIDE_NODES;
}
sideNodes.push_back( sideNode );
// sew the border to the side 2
// ============================
- int nbNodes[] = { nSide[0].size(), nSide[1].size() };
+ int nbNodes[] = { (int)nSide[0].size(), (int)nSide[1].size() };
int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
+ bool toMergeConformal = ( nbNodes[0] == nbNodes[1] );
+ if ( toMergeConformal && toCreatePolygons )
+ {
+ // do not merge quadrangles if polygons are OK (IPAL0052824)
+ eIt[0] = eSide[0].begin();
+ eIt[1] = eSide[1].begin();
+ bool allQuads[2] = { true, true };
+ for ( int iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
+ for ( ; allQuads[iBord] && eIt[iBord] != eSide[iBord].end(); ++eIt[iBord] )
+ allQuads[iBord] = ( (*eIt[iBord])->NbCornerNodes() == 4 );
+ }
+ toMergeConformal = ( !allQuads[0] && !allQuads[1] );
+ }
+
TListOfListOfNodes nodeGroupsToMerge;
- if ( nbNodes[0] == nbNodes[1] ||
- ( theSideIsFreeBorder && !theSideThirdNode)) {
+ if (( toMergeConformal ) ||
+ ( theSideIsFreeBorder && !theSideThirdNode )) {
// all nodes are to be merged
// 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 ];
- param[0] = new double [ maxNbNodes ];
- param[1] = new double [ maxNbNodes ];
+ vector< double > param[ 2 ];
+ param[0].resize( maxNbNodes );
+ param[1].resize( maxNbNodes );
int iNode, iBord;
for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
+ // element can be split while iterating on border if it has two edges in the border
+ std::map< const SMDS_MeshElement* , const SMDS_MeshElement* > elemReplaceMap;
+ std::map< const SMDS_MeshElement* , const SMDS_MeshElement* >::iterator elemReplaceMapIt;
+
TElemOfNodeListMap insertMap;
TElemOfNodeListMap::iterator insertMapIt;
// insertMap is
if ( i[ iBord ] > 0 )
prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
}
- double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
- double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
+ double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
+ double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
// choose to insert or to merge nodes
// insert
// ------
int intoBord = ( du < 0 ) ? 0 : 1;
- const SMDS_MeshElement* elem = *eIt[ intoBord ];
+ const SMDS_MeshElement* elem = *eIt [ intoBord ];
const SMDS_MeshNode* n1 = nPrev[ intoBord ];
- const SMDS_MeshNode* n2 = *nIt[ intoBord ];
- const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
+ const SMDS_MeshNode* n2 = *nIt [ intoBord ];
+ const SMDS_MeshNode* nIns = *nIt [ 1 - intoBord ];
if ( intoBord == 1 ) {
// move node of the border to be on a link of elem of the side
- gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
- gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
+ SMESH_NodeXYZ p1( n1 ), p2( n2 );
double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
}
+ elemReplaceMapIt = elemReplaceMap.find( elem );
+ if ( elemReplaceMapIt != elemReplaceMap.end() )
+ elem = elemReplaceMapIt->second;
+
insertMapIt = insertMap.find( elem );
- bool notFound = ( insertMapIt == insertMap.end() );
+ bool notFound = ( insertMapIt == insertMap.end() );
bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
if ( otherLink ) {
// insert into another link of the same element:
const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
// 2. perform insertion into the link of adjacent faces
- while (true) {
- const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
- if ( adjElem )
- InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
- else
- break;
+ while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem )) {
+ InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
+ }
+ while ( const SMDS_MeshElement* seg = findSegment( n12, n22 )) {
+ InsertNodesIntoLink( seg, n12, n22, nodeList );
}
if (toCreatePolyedrs) {
// perform insertion into the links of adjacent volumes
UpdateVolumes(n12, n22, nodeList);
}
// 3. find an element appeared on n1 and n2 after the insertion
- insertMap.erase( elem );
- elem = findAdjacentFace( n1, n2, 0 );
+ insertMap.erase( insertMapIt );
+ const SMDS_MeshElement* elem2 = findAdjacentFace( n1, n2, 0 );
+ elemReplaceMap.insert( std::make_pair( elem, elem2 ));
+ elem = elem2;
}
if ( notFound || otherLink ) {
// add element and nodes of the side into the insertMap
- insertMapIt = insertMap.insert
- ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
+ insertMapIt = insertMap.insert( make_pair( elem, list<const SMDS_MeshNode*>() )).first;
(*insertMapIt).second.push_back( n1 );
(*insertMapIt).second.push_back( n2 );
}
{
const SMDS_MeshElement* elem = (*insertMapIt).first;
list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
+ if ( nodeList.size() < 3 ) continue;
const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
+ while ( const SMDS_MeshElement* seg = findSegment( n1, n2 )) {
+ InsertNodesIntoLink( seg, n1, n2, nodeList );
+ }
+
if ( !theSideIsFreeBorder ) {
// look for and insert nodes into the faces adjacent to elem
- while (true) {
- const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
- if ( adjElem )
- InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
- else
- break;
+ while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem )) {
+ InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
}
}
if (toCreatePolyedrs) {
UpdateVolumes(n1, n2, nodeList);
}
}
-
- delete param[0];
- delete param[1];
} // end: insert new nodes
MergeNodes ( nodeGroupsToMerge );
+
+ // Remove coincident segments
+
+ // get new segments
+ TIDSortedElemSet segments;
+ SMESH_SequenceOfElemPtr newFaces;
+ for ( size_t i = 0; i < myLastCreatedElems.size(); ++i )
+ {
+ if ( !myLastCreatedElems[i] ) continue;
+ if ( myLastCreatedElems[i]->GetType() == SMDSAbs_Edge )
+ segments.insert( segments.end(), myLastCreatedElems[i] );
+ else
+ newFaces.push_back( myLastCreatedElems[i] );
+ }
+ // get segments adjacent to merged nodes
+ TListOfListOfNodes::iterator groupIt = nodeGroupsToMerge.begin();
+ for ( ; groupIt != nodeGroupsToMerge.end(); groupIt++ )
+ {
+ const list<const SMDS_MeshNode*>& nodes = *groupIt;
+ if ( nodes.front()->IsNull() ) continue;
+ SMDS_ElemIteratorPtr segIt = nodes.front()->GetInverseElementIterator( SMDSAbs_Edge );
+ while ( segIt->more() )
+ segments.insert( segIt->next() );
+ }
+
+ // find coincident
+ TListOfListOfElementsID equalGroups;
+ if ( !segments.empty() )
+ FindEqualElements( segments, equalGroups );
+ if ( !equalGroups.empty() )
+ {
+ // remove from segments those that will be removed
+ TListOfListOfElementsID::iterator itGroups = equalGroups.begin();
+ for ( ; itGroups != equalGroups.end(); ++itGroups )
+ {
+ list< smIdType >& group = *itGroups;
+ list< smIdType >::iterator id = group.begin();
+ for ( ++id; id != group.end(); ++id )
+ if ( const SMDS_MeshElement* seg = GetMeshDS()->FindElement( *id ))
+ segments.erase( seg );
+ }
+ // remove equal segments
+ MergeElements( equalGroups );
+
+ // restore myLastCreatedElems
+ myLastCreatedElems = newFaces;
+ TIDSortedElemSet::iterator seg = segments.begin();
+ for ( ; seg != segments.end(); ++seg )
+ myLastCreatedElems.push_back( *seg );
+ }
+
return aResult;
}
//=======================================================================
//function : InsertNodesIntoLink
-//purpose : insert theNodesToInsert into theFace between theBetweenNode1
+//purpose : insert theNodesToInsert into theElement between theBetweenNode1
// and theBetweenNode2 and split theElement
//=======================================================================
-void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
+void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theElement,
const SMDS_MeshNode* theBetweenNode1,
const SMDS_MeshNode* theBetweenNode2,
list<const SMDS_MeshNode*>& theNodesToInsert,
const bool toCreatePoly)
{
+ if ( !theElement ) return;
+
+ SMESHDS_Mesh *aMesh = GetMeshDS();
+ vector<const SMDS_MeshElement*> newElems;
+
+ if ( theElement->GetType() == SMDSAbs_Edge )
+ {
+ theNodesToInsert.push_front( theBetweenNode1 );
+ theNodesToInsert.push_back ( theBetweenNode2 );
+ list<const SMDS_MeshNode*>::iterator n = theNodesToInsert.begin();
+ const SMDS_MeshNode* n1 = *n;
+ for ( ++n; n != theNodesToInsert.end(); ++n )
+ {
+ const SMDS_MeshNode* n2 = *n;
+ if ( const SMDS_MeshElement* seg = aMesh->FindEdge( n1, n2 ))
+ AddToSameGroups( seg, theElement, aMesh );
+ else
+ newElems.push_back( aMesh->AddEdge ( n1, n2 ));
+ n1 = n2;
+ }
+ theNodesToInsert.pop_front();
+ theNodesToInsert.pop_back();
+
+ if ( theElement->IsQuadratic() ) // add a not split part
+ {
+ vector<const SMDS_MeshNode*> nodes( theElement->begin_nodes(),
+ theElement->end_nodes() );
+ int iOther = 0, nbN = nodes.size();
+ for ( ; iOther < nbN; ++iOther )
+ if ( nodes[iOther] != theBetweenNode1 &&
+ nodes[iOther] != theBetweenNode2 )
+ break;
+ if ( iOther == 0 )
+ {
+ if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[0], nodes[1] ))
+ AddToSameGroups( seg, theElement, aMesh );
+ else
+ newElems.push_back( aMesh->AddEdge ( nodes[0], nodes[1] ));
+ }
+ else if ( iOther == 2 )
+ {
+ if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[1], nodes[2] ))
+ AddToSameGroups( seg, theElement, aMesh );
+ else
+ newElems.push_back( aMesh->AddEdge ( nodes[1], nodes[2] ));
+ }
+ }
+ // treat new elements
+ for ( size_t i = 0; i < newElems.size(); ++i )
+ if ( newElems[i] )
+ {
+ aMesh->SetMeshElementOnShape( newElems[i], theElement->getshapeId() );
+ myLastCreatedElems.push_back( newElems[i] );
+ }
+ ReplaceElemInGroups( theElement, newElems, aMesh );
+ aMesh->RemoveElement( theElement );
+ return;
+
+ } // if ( theElement->GetType() == SMDSAbs_Edge )
+
+ const SMDS_MeshElement* theFace = theElement;
if ( theFace->GetType() != SMDSAbs_Face ) return;
// 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() ];
vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
- if(theFace->IsQuadratic()) {
- 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_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
- while( anIter->more() ) {
- const SMDS_MeshNode* n = cast2Node(anIter->next());
- if ( n == theBetweenNode1 )
- il1 = iNode;
- else if ( n == theBetweenNode2 )
- il2 = iNode;
- else if ( i3 < 0 )
- i3 = iNode;
- else
- i4 = iNode;
- nodes[ iNode++ ] = n;
- }
- }
- else {
- SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
- while ( nodeIt->more() ) {
- const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
- if ( n == theBetweenNode1 )
- il1 = iNode;
- else if ( n == theBetweenNode2 )
- il2 = iNode;
- else if ( i3 < 0 )
- i3 = iNode;
- else
- i4 = iNode;
- nodes[ iNode++ ] = n;
- }
+ SMDS_NodeIteratorPtr nodeIt = theFace->interlacedNodesIterator();
+ while ( nodeIt->more() ) {
+ const SMDS_MeshNode* n = nodeIt->next();
+ if ( n == theBetweenNode1 )
+ il1 = iNode;
+ else if ( n == theBetweenNode2 )
+ il2 = iNode;
+ else if ( i3 < 0 )
+ i3 = iNode;
+ else
+ i4 = iNode;
+ nodes[ iNode++ ] = n;
}
if ( il1 < 0 || il2 < 0 || i3 < 0 )
return ;
// add nodes of face up to first node of link
bool isFLN = false;
-
- if(theFace->IsQuadratic()) {
- 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_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
- while( anIter->more() && !isFLN ) {
- const SMDS_MeshNode* n = cast2Node(anIter->next());
- poly_nodes[iNode++] = n;
- if (n == nodes[il1]) {
- isFLN = true;
- }
- }
- // add nodes to insert
- list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
- for (; nIt != aNodesToInsert.end(); nIt++) {
- poly_nodes[iNode++] = *nIt;
- }
- // add nodes of face starting from last node of link
- while ( anIter->more() ) {
- poly_nodes[iNode++] = cast2Node(anIter->next());
- }
+ SMDS_NodeIteratorPtr nodeIt = theFace->interlacedNodesIterator();
+ while ( nodeIt->more() && !isFLN ) {
+ const SMDS_MeshNode* n = nodeIt->next();
+ poly_nodes[iNode++] = n;
+ isFLN = ( n == nodes[il1] );
}
- else {
- SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
- while ( nodeIt->more() && !isFLN ) {
- const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
- poly_nodes[iNode++] = n;
- if (n == nodes[il1]) {
- isFLN = true;
- }
- }
- // add nodes to insert
- list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
- for (; nIt != aNodesToInsert.end(); nIt++) {
- poly_nodes[iNode++] = *nIt;
- }
- // add nodes of face starting from last node of link
- while ( nodeIt->more() ) {
- const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
- poly_nodes[iNode++] = n;
- }
+ // add nodes to insert
+ list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
+ for (; nIt != aNodesToInsert.end(); nIt++) {
+ poly_nodes[iNode++] = *nIt;
}
-
- // edit or replace the face
- SMESHDS_Mesh *aMesh = GetMeshDS();
-
- if (theFace->IsPoly()) {
- aMesh->ChangePolygonNodes(theFace, poly_nodes);
+ // add nodes of face starting from last node of link
+ while ( nodeIt->more() ) {
+ const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+ poly_nodes[iNode++] = n;
}
- else {
- int aShapeId = FindShape( theFace );
- SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
-
- aMesh->RemoveElement(theFace);
- }
- return;
+ // make a new face
+ newElems.push_back( aMesh->AddPolygonalFace( poly_nodes ));
}
- SMESHDS_Mesh *aMesh = GetMeshDS();
- if( !theFace->IsQuadratic() ) {
-
+ else if ( !theFace->IsQuadratic() )
+ {
// put aNodesToInsert between theBetweenNode1 and theBetweenNode2
int nbLinkNodes = 2 + aNodesToInsert.size();
//const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
}
// decide how to split a quadrangle: compare possible variants
// and choose which of splits to be a quadrangle
- int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
+ int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad = 0;
if ( nbFaceNodes == 3 ) {
iBestQuad = nbSplits;
i4 = i3;
}
// create new elements
- int aShapeId = FindShape( theFace );
-
i1 = 0; i2 = 1;
- for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
- SMDS_MeshElement* newElem = 0;
+ for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ )
+ {
if ( iSplit == iBestQuad )
- newElem = aMesh->AddFace (linkNodes[ i1++ ],
- linkNodes[ i2++ ],
- nodes[ i3 ],
- nodes[ i4 ]);
+ newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ],
+ linkNodes[ i2++ ],
+ nodes[ i3 ],
+ nodes[ i4 ]));
else
- newElem = aMesh->AddFace (linkNodes[ i1++ ],
- linkNodes[ i2++ ],
- nodes[ iSplit < iBestQuad ? i4 : i3 ]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ],
+ linkNodes[ i2++ ],
+ nodes[ iSplit < iBestQuad ? i4 : i3 ]));
}
- // 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 );
- const SMDS_MeshElement* newElem = 0;
if (iSplit == iBestQuad)
- newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
+ newElems.push_back( 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())
+ newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] ));
+
+ } // end if(!theFace->IsQuadratic())
+
else { // theFace is quadratic
// we have to split theFace on simple triangles and one simple quadrangle
int tmp = il1/2;
// n4 n6 n5 n4
// create new elements
- int aShapeId = FindShape( theFace );
-
int n1,n2,n3;
- if(nbFaceNodes==6) { // quadratic triangle
- SMDS_MeshElement* newElem =
- aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- if(theFace->IsMediumNode(nodes[il1])) {
+ if ( nbFaceNodes == 6 ) { // quadratic triangle
+ newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] ));
+ if ( theFace->IsMediumNode(nodes[il1]) ) {
// create quadrangle
- newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[5] ));
n1 = 1;
n2 = 2;
n3 = 3;
}
else {
// create quadrangle
- newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[5] ));
n1 = 0;
n2 = 1;
n3 = 5;
}
}
else { // nbFaceNodes==8 - quadratic quadrangle
- SMDS_MeshElement* newElem =
- aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- if(theFace->IsMediumNode(nodes[il1])) {
+ newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] ));
+ newElems.push_back( aMesh->AddFace( nodes[5], nodes[6], nodes[7] ));
+ newElems.push_back( aMesh->AddFace( nodes[5], nodes[7], nodes[3] ));
+ if ( theFace->IsMediumNode( nodes[ il1 ])) {
// create quadrangle
- newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[7] ));
n1 = 1;
n2 = 2;
n3 = 3;
}
else {
// create quadrangle
- newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[7] ));
n1 = 0;
n2 = 1;
n3 = 7;
}
// create needed triangles using n1,n2,n3 and inserted nodes
int nbn = 2 + aNodesToInsert.size();
- //const SMDS_MeshNode* aNodes[nbn];
vector<const SMDS_MeshNode*> aNodes(nbn);
- aNodes[0] = nodes[n1];
+ aNodes[0 ] = nodes[n1];
aNodes[nbn-1] = nodes[n2];
list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
aNodes[iNode++] = *nIt;
}
- for(i=1; i<nbn; i++) {
- SMDS_MeshElement* newElem =
- aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- }
+ for ( i = 1; i < nbn; i++ )
+ newElems.push_back( aMesh->AddFace( aNodes[i-1], aNodes[i], nodes[n3] ));
}
- // remove old face
+
+ // remove the old face
+ for ( size_t i = 0; i < newElems.size(); ++i )
+ if ( newElems[i] )
+ {
+ aMesh->SetMeshElementOnShape( newElems[i], theFace->getshapeId() );
+ myLastCreatedElems.push_back( newElems[i] );
+ }
+ ReplaceElemInGroups( theFace, newElems, aMesh );
aMesh->RemoveElement(theFace);
-}
+
+} // InsertNodesIntoLink()
//=======================================================================
//function : UpdateVolumes
//purpose :
//=======================================================================
+
void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
const SMDS_MeshNode* theBetweenNode2,
list<const SMDS_MeshNode*>& theNodesToInsert)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
quantities[iface] = nbFaceNodes + nbInserted;
}
- // Replace or update the volume
+ // Replace the volume
SMESHDS_Mesh *aMesh = GetMeshDS();
- if (elem->IsPoly()) {
- aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
-
- }
- else {
- int aShapeId = FindShape( elem );
-
- SMDS_MeshElement* newElem =
- aMesh->AddPolyhedralVolume(poly_nodes, quantities);
- myLastCreatedElems.Append(newElem);
- if (aShapeId && newElem)
- aMesh->SetMeshElementOnShape(newElem, aShapeId);
-
- aMesh->RemoveElement(elem);
+ if ( SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities ))
+ {
+ aMesh->SetMeshElementOnShape( newElem, elem->getshapeId() );
+ myLastCreatedElems.push_back( newElem );
+ ReplaceElemInGroups( elem, newElem, aMesh );
}
+ aMesh->RemoveElement( elem );
}
}
//=======================================================================
/*!
- * \brief Convert elements contained in a submesh to quadratic
+ * \brief Convert elements contained in a sub-mesh to quadratic
* \return int - nb of checked elements
*/
//=======================================================================
-int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
- SMESH_MesherHelper& theHelper,
- const bool theForce3d)
+smIdType SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
+ SMESH_MesherHelper& theHelper,
+ const bool theForce3d)
{
- int nbElem = 0;
+ //MESSAGE("convertElemToQuadratic");
+ smIdType nbElem = 0;
if( !theSm ) return nbElem;
vector<int> nbNodeInFaces;
const SMDS_MeshElement* elem = ElemItr->next();
if( !elem ) continue;
+ // analyse a necessity of conversion
+ const SMDSAbs_ElementType aType = elem->GetType();
+ if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
+ continue;
const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
+ bool hasCentralNodes = false;
if ( elem->IsQuadratic() )
{
bool alreadyOK;
switch ( aGeomType ) {
+ case SMDSEntity_Quad_Triangle:
case SMDSEntity_Quad_Quadrangle:
- case SMDSEntity_Quad_Hexa: alreadyOK = !theHelper.GetIsBiQuadratic(); break;
+ case SMDSEntity_Quad_Hexa:
+ case SMDSEntity_Quad_Penta:
+ alreadyOK = !theHelper.GetIsBiQuadratic(); break;
+
+ case SMDSEntity_BiQuad_Triangle:
case SMDSEntity_BiQuad_Quadrangle:
- case SMDSEntity_TriQuad_Hexa: alreadyOK = theHelper.GetIsBiQuadratic(); break;
- default: alreadyOK = true;
- }
- if ( alreadyOK ) continue;
+ case SMDSEntity_TriQuad_Hexa:
+ case SMDSEntity_BiQuad_Penta:
+ alreadyOK = theHelper.GetIsBiQuadratic();
+ hasCentralNodes = true;
+ break;
+ default:
+ alreadyOK = true;
+ }
+ // take into account already present medium nodes
+ switch ( aType ) {
+ case SMDSAbs_Volume:
+ theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
+ case SMDSAbs_Face:
+ theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
+ case SMDSAbs_Edge:
+ theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
+ default:;
+ }
+ if ( alreadyOK )
+ continue;
}
// get elem data needed to re-create it
//
- const int id = elem->GetID();
- const int nbNodes = elem->NbCornerNodes();
- const SMDSAbs_ElementType aType = elem->GetType();
+ const smIdType id = elem->GetID();
+ const int nbNodes = elem->NbCornerNodes();
nodes.assign(elem->begin_nodes(), elem->end_nodes());
if ( aGeomType == SMDSEntity_Polyhedra )
- nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
+ nbNodeInFaces = static_cast<const SMDS_MeshVolume* >( elem )->GetQuantities();
else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
volumeToPolyhedron( elem, nodes, nbNodeInFaces );
// remove a linear element
GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
+ // remove central nodes of biquadratic elements (biquad->quad conversion)
+ if ( hasCentralNodes )
+ for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
+ if ( nodes[i]->NbInverseElements() == 0 )
+ GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
+
const SMDS_MeshElement* NewElem = 0;
switch( aType )
{
case SMDSAbs_Edge :
- {
- NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
- break;
- }
+ {
+ NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
+ break;
+ }
case SMDSAbs_Face :
+ {
+ switch(nbNodes)
{
- 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;
- }
+ 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);
}
+ break;
+ }
case SMDSAbs_Volume :
+ {
+ switch( aGeomType )
{
- switch( aGeomType )
- {
- case SMDSEntity_Tetra:
- NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
- break;
- case SMDSEntity_Pyramid:
- NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
- break;
- case SMDSEntity_Penta:
- NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
- break;
- case SMDSEntity_Hexa:
- case SMDSEntity_Quad_Hexa:
- case SMDSEntity_TriQuad_Hexa:
- NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
- nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
- break;
- case SMDSEntity_Hexagonal_Prism:
- default:
- NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
- }
+ case SMDSEntity_Tetra:
+ NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+ break;
+ case SMDSEntity_Pyramid:
+ NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
+ break;
+ case SMDSEntity_Penta:
+ case SMDSEntity_Quad_Penta:
+ case SMDSEntity_BiQuad_Penta:
+ NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
+ break;
+ case SMDSEntity_Hexa:
+ case SMDSEntity_Quad_Hexa:
+ case SMDSEntity_TriQuad_Hexa:
+ NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
break;
+ case SMDSEntity_Hexagonal_Prism:
+ default:
+ NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
}
+ break;
+ }
default :
continue;
}
ReplaceElemInGroups( elem, NewElem, GetMeshDS());
- if( NewElem )
+ if( NewElem && NewElem->getshapeId() < 1 )
theSm->AddElement( NewElem );
}
return nbElem;
void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
{
+ //MESSAGE("ConvertToQuadratic "<< theForce3d << " " << theToBiQuad);
SMESHDS_Mesh* meshDS = GetMeshDS();
SMESH_MesherHelper aHelper(*myMesh);
aHelper.SetIsQuadratic( true );
aHelper.SetIsBiQuadratic( theToBiQuad );
aHelper.SetElementsOnShape(true);
+ aHelper.ToFixNodeParameters( true );
- int nbCheckedElems = 0;
+ // convert elements assigned to sub-meshes
+ smIdType nbCheckedElems = 0;
if ( myMesh->HasShapeToMesh() )
{
if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
}
}
}
- int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
- if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
+
+ // convert elements NOT assigned to sub-meshes
+ smIdType totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
+ if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
{
aHelper.SetElementsOnShape(false);
SMESHDS_SubMesh *smDS = 0;
+
+ // convert edges
SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
- while(aEdgeItr->more())
+ while( aEdgeItr->more() )
{
const SMDS_MeshEdge* edge = aEdgeItr->next();
- if(edge && !edge->IsQuadratic())
+ if ( !edge->IsQuadratic() )
{
- int id = edge->GetID();
- //MESSAGE("edge->GetID() " << id);
+ smIdType id = edge->GetID();
const SMDS_MeshNode* n1 = edge->GetNode(0);
const SMDS_MeshNode* n2 = edge->GetNode(1);
const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
}
+ else
+ {
+ aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
+ }
}
+
+ // convert faces
SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
- while(aFaceItr->more())
+ while( aFaceItr->more() )
{
const SMDS_MeshFace* face = aFaceItr->next();
if ( !face ) continue;
const SMDSAbs_EntityType type = face->GetEntityType();
- if (( theToBiQuad && type == SMDSEntity_BiQuad_Quadrangle ) ||
- ( !theToBiQuad && type == SMDSEntity_Quad_Quadrangle ))
+ bool alreadyOK;
+ switch( type )
+ {
+ case SMDSEntity_Quad_Triangle:
+ case SMDSEntity_Quad_Quadrangle:
+ alreadyOK = !theToBiQuad;
+ aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
+ break;
+ case SMDSEntity_BiQuad_Triangle:
+ case SMDSEntity_BiQuad_Quadrangle:
+ alreadyOK = theToBiQuad;
+ aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
+ break;
+ default: alreadyOK = false;
+ }
+ if ( alreadyOK )
continue;
- const int id = face->GetID();
+ const smIdType id = face->GetID();
vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
switch( type )
{
case SMDSEntity_Triangle:
+ case SMDSEntity_Quad_Triangle:
+ case SMDSEntity_BiQuad_Triangle:
NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
+ if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
+ GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
break;
+
case SMDSEntity_Quadrangle:
+ case SMDSEntity_Quad_Quadrangle:
+ case SMDSEntity_BiQuad_Quadrangle:
NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+ if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
+ GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
break;
- default:
+
+ default:;
NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
}
ReplaceElemInGroups( face, NewFace, GetMeshDS());
}
+
+ // convert volumes
vector<int> nbNodeInFaces;
SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
while(aVolumeItr->more())
{
const SMDS_MeshVolume* volume = aVolumeItr->next();
- if(!volume || volume->IsQuadratic() ) continue;
+ if ( !volume ) continue;
const SMDSAbs_EntityType type = volume->GetEntityType();
- if (( theToBiQuad && type == SMDSEntity_TriQuad_Hexa ) ||
- ( !theToBiQuad && type == SMDSEntity_Quad_Hexa ))
- continue;
-
- const int id = volume->GetID();
+ if ( volume->IsQuadratic() )
+ {
+ bool alreadyOK;
+ switch ( type )
+ {
+ case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break;
+ case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
+ case SMDSEntity_Quad_Penta: alreadyOK = !theToBiQuad; break;
+ case SMDSEntity_BiQuad_Penta: alreadyOK = theToBiQuad; break;
+ default: alreadyOK = true;
+ }
+ if ( alreadyOK )
+ {
+ aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
+ continue;
+ }
+ }
+ const smIdType id = volume->GetID();
vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
if ( type == SMDSEntity_Polyhedra )
- nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
+ nbNodeInFaces = static_cast<const SMDS_MeshVolume* >(volume)->GetQuantities();
else if ( type == SMDSEntity_Hexagonal_Prism )
volumeToPolyhedron( volume, nodes, nbNodeInFaces );
case SMDSEntity_TriQuad_Hexa:
NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
+ for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
+ if ( nodes[i]->NbInverseElements() == 0 )
+ GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
break;
case SMDSEntity_Pyramid:
NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
nodes[3], nodes[4], id, theForce3d);
break;
case SMDSEntity_Penta:
+ case SMDSEntity_Quad_Penta:
+ case SMDSEntity_BiQuad_Penta:
NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
nodes[3], nodes[4], nodes[5], id, theForce3d);
+ for ( size_t i = 15; i < nodes.size(); ++i ) // rm central nodes
+ if ( nodes[i]->NbInverseElements() == 0 )
+ GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
break;
case SMDSEntity_Hexagonal_Prism:
default:
if ( !theForce3d )
{ // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
- aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
- aHelper.FixQuadraticElements(myError);
+ // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+ // aHelper.FixQuadraticElements(myError);
+ SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
}
}
SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
while ( invIt->more() )
{
- const SMDS_MeshElement* e = invIt->next();
+ const SMDS_MeshElement* e = invIt->next();
+ const SMDSAbs_ElementType type = e->GetType();
if ( e->IsQuadratic() )
{
+ quadAdjacentElems[ type ].insert( e );
+
bool alreadyOK;
switch ( e->GetEntityType() ) {
+ case SMDSEntity_Quad_Triangle:
case SMDSEntity_Quad_Quadrangle:
case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break;
+ case SMDSEntity_BiQuad_Triangle:
case SMDSEntity_BiQuad_Quadrangle:
case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
default: alreadyOK = true;
}
if ( alreadyOK )
- {
- quadAdjacentElems[ e->GetType() ].insert( e );
continue;
- }
- }
- if ( e->GetType() >= elemType )
- {
- continue; // same type of more complex linear element
}
+ if ( type >= elemType )
+ continue; // same type or more complex linear element
- if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
+ if ( !checkedAdjacentElems[ type ].insert( e ).second )
continue; // e is already checked
// check nodes
bool allIn = true;
- SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
+ SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
while ( nodeIt->more() && allIn )
- allIn = allNodes.count( cast2Node( nodeIt->next() ));
+ allIn = allNodes.count( nodeIt->next() );
if ( allIn )
theElements.insert(e );
}
for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
{
const SMDS_MeshElement* elem = *eIt;
- if( elem->NbNodes() < 2 || elem->IsPoly() )
- continue;
- if ( elem->IsQuadratic() )
- {
- bool alreadyOK;
- switch ( elem->GetEntityType() ) {
- case SMDSEntity_Quad_Quadrangle:
- case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break;
- case SMDSEntity_BiQuad_Quadrangle:
- case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
- default: alreadyOK = true;
- }
- if ( alreadyOK ) continue;
- }
+ bool alreadyOK;
+ int nbCentralNodes = 0;
+ switch ( elem->GetEntityType() ) {
+ // linear convertible
+ case SMDSEntity_Edge:
+ case SMDSEntity_Triangle:
+ case SMDSEntity_Quadrangle:
+ case SMDSEntity_Tetra:
+ case SMDSEntity_Pyramid:
+ case SMDSEntity_Hexa:
+ case SMDSEntity_Penta: alreadyOK = false; nbCentralNodes = 0; break;
+ // quadratic that can become bi-quadratic
+ case SMDSEntity_Quad_Triangle:
+ case SMDSEntity_Quad_Quadrangle:
+ case SMDSEntity_Quad_Hexa: alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
+ // bi-quadratic
+ case SMDSEntity_BiQuad_Triangle:
+ case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
+ case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
+ // the rest
+ default: alreadyOK = true;
+ }
+ if ( alreadyOK ) continue;
const SMDSAbs_ElementType type = elem->GetType();
- const int id = elem->GetID();
+ const smIdType id = elem->GetID();
const int nbNodes = elem->NbCornerNodes();
vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
+ helper.SetSubShape( elem->getshapeId() );
+
if ( !smDS || !smDS->Contains( elem ))
smDS = meshDS->MeshElements( elem->getshapeId() );
meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
ReplaceElemInGroups( elem, newElem, meshDS);
if( newElem && smDS )
smDS->AddElement( newElem );
- }
- if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
+ // remove central nodes
+ for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
+ if ( nodes[i]->NbInverseElements() == 0 )
+ meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
+
+ } // loop on theElements
+
+ if ( !theForce3d )
{ // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
- helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
- helper.FixQuadraticElements( myError );
+ // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+ // helper.FixQuadraticElements( myError );
+ SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
}
}
//=======================================================================
/*!
* \brief Convert quadratic elements to linear ones and remove quadratic nodes
- * \return int - nb of checked elements
+ * \return smIdType - nb of checked elements
*/
//=======================================================================
-int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
- SMDS_ElemIteratorPtr theItr,
- const int theShapeID)
+smIdType SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
+ SMDS_ElemIteratorPtr theItr,
+ const int /*theShapeID*/)
{
- int nbElem = 0;
+ smIdType nbElem = 0;
SMESHDS_Mesh* meshDS = GetMeshDS();
+ ElemFeatures elemType;
+ vector<const SMDS_MeshNode *> nodes;
while( theItr->more() )
{
nbElem++;
if( elem && elem->IsQuadratic())
{
- int id = elem->GetID();
- int nbCornerNodes = elem->NbCornerNodes();
- SMDSAbs_ElementType aType = elem->GetType();
+ // get elem data
+ int nbCornerNodes = elem->NbCornerNodes();
+ nodes.assign( elem->begin_nodes(), elem->end_nodes() );
- vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
+ elemType.Init( elem, /*basicOnly=*/false ).SetID( elem->GetID() ).SetQuad( false );
//remove a quadratic element
if ( !theSm || !theSm->Contains( elem ))
meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
// remove medium nodes
- for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
+ for ( size_t i = nbCornerNodes; i < nodes.size(); ++i )
if ( nodes[i]->NbInverseElements() == 0 )
meshDS->RemoveFreeNode( nodes[i], theSm );
// add a linear element
nodes.resize( nbCornerNodes );
- SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
+ SMDS_MeshElement * newElem = AddElement( nodes, elemType );
ReplaceElemInGroups(elem, newElem, meshDS);
if( theSm && newElem )
theSm->AddElement( newElem );
bool SMESH_MeshEditor::ConvertFromQuadratic()
{
- int nbCheckedElems = 0;
+ smIdType nbCheckedElems = 0;
if ( myMesh->HasShapeToMesh() )
{
if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
}
}
- int totalNbElems =
+ smIdType totalNbElems =
GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
{
if ( theElements.empty() ) return;
// collect IDs of medium nodes of theElements; some of these nodes will be removed
- set<int> mediumNodeIDs;
+ set<smIdType> mediumNodeIDs;
TIDSortedElemSet::iterator eIt = theElements.begin();
for ( ; eIt != theElements.end(); ++eIt )
{
}
// replace given elements by linear ones
- typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
- SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
+ SMDS_ElemIteratorPtr elemIt = SMESHUtils::elemSetIterator( theElements );
removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
// we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
// get remaining medium nodes
TIDSortedNodeSet mediumNodes;
- set<int>::iterator nIdsIt = mediumNodeIDs.begin();
+ set<smIdType>::iterator nIdsIt = mediumNodeIDs.begin();
for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
mediumNodes.insert( mediumNodes.end(), n );
const SMDS_MeshElement* eComplex = invIt2->next();
if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
{
- int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
+ int nbCommonNodes = SMESH_MeshAlgos::NbCommonNodes( e, eComplex );
if ( nbCommonNodes == e->NbNodes())
{
complexFound = true;
}
}
}
- elemIt = SMDS_ElemIteratorPtr
- (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
+ elemIt = SMESHUtils::elemSetIterator( moreElemsToConvert );
removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
}
const SMDS_MeshNode* theSecondNode1,
const SMDS_MeshNode* theSecondNode2)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
- MESSAGE ("::::SewSideElements()");
if ( theSide1.size() != theSide2.size() )
return SEW_DIFF_NB_OF_ELEMENTS;
// face does not exist
SMESHDS_Mesh* aMesh = GetMeshDS();
- // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
+ // TODO algorithm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
//SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
TIDSortedElemSet faceSet1, faceSet2;
set<const SMDS_MeshElement*> volSet1, volSet2;
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() );
-// list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
-// for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
-// aMesh->RemoveElement(*tmpFaceIt);
+ // 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;
}
//cout << "Side " << iSide << " ";
//cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
// find a face by two link nodes
- face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
- &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
+ face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
+ *faceSetPtr[ iSide ], avoidSet,
+ &iLinkNode[iSide][0],
+ &iLinkNode[iSide][1] );
if ( face[ iSide ])
{
//cout << " F " << face[ iSide]->GetID() <<endl;
faceSetPtr[ iSide ]->erase( face[ iSide ]);
// put face nodes to fnodes
- if ( face[ iSide ]->IsQuadratic() )
+ SMDS_MeshElement::iterator nIt( face[ iSide ]->interlacedNodesIterator() ), nEnd;
+ fnodes[ iSide ].assign( nIt, nEnd );
+ fnodes[ iSide ].push_back( fnodes[ iSide ].front());
+ }
+ }
+
+ // 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] ) {
+ const 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 nodes in the link
+ 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;
+ }
+ int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
+ int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
+ for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
+ {
+ nReplaceMap.insert ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
+ fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
+ }
+
+ // add other links of the faces to linkList
+ // -----------------------------------------
+
+ for ( iNode = 0; iNode < nbNodes; iNode++ ) {
+ linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][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
{
- // use interlaced nodes iterator
- const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
- if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
- SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
- while ( nIter->more() )
- fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
+ const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
+ const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
+ linkList[0].push_back ( NLink( n1, n2 ));
+ linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
}
- else
+ }
+ } // 2 faces found
+
+ if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
+ break;
+
+ } // 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
+ // 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< smIdType > nodeIDsToRemove;
+ vector< const SMDS_MeshNode*> nodes;
+ ElemFeatures elemType;
+
+ // 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();
+ nodes.resize( 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 )
{
- fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
- face[ iSide ]->end_nodes() );
+ elemType.Init( e, /*basicOnly=*/false ).SetID( e->GetID() );
+ aMesh->RemoveElement( e );
+
+ if ( SMDS_MeshElement* newElem = this->AddElement( nodes, elemType ))
+ {
+ AddToSameGroups( newElem, e, aMesh );
+ if ( int aShapeId = e->getshapeId() )
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
+ }
+ }
+ }
+ }
+
+ 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
+ * \return 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 ) );
+ }
+ }
}
- fnodes[ iSide ].push_back( fnodes[ iSide ].front());
}
}
-
// check similarity of elements of the sides
- if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
+ 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
- aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
+ return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
}
else {
- aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
+ return 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] ) {
- const int nbNodes = face[0]->NbNodes();
- if ( nbNodes != face[1]->NbNodes() ) {
+ if ( nbNodes[0] != nbNodes[1] ) {
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 nodes in the link
- 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;
+ return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
}
- int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
- int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
- for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
+#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];
{
- nReplaceMap.insert ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
- fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
+ 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 faces to linkList
+ // add other links of the face 1 to linkList
// -----------------------------------------
- for ( iNode = 0; iNode < nbNodes; iNode++ ) {
- linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
- pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
+ 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
- linkIdSet.erase( iter_isnew.first );
+ linkSet.erase( iter_isnew.first );
}
else // new in set == encountered for the first time: add
{
- const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
- const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
+#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
- if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
- break;
+ return SEW_OK;
+}
- } // loop on link lists
+namespace // automatically find theAffectedElems for DoubleNodes()
+{
+ bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem );
- 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;
+ //--------------------------------------------------------------------------------
+ // Nodes shared by adjacent FissureBorder's.
+ // 1 node if FissureBorder separates faces
+ // 2 nodes if FissureBorder separates volumes
+ struct SubBorder
+ {
+ const SMDS_MeshNode* _nodes[2];
+ int _nbNodes;
+
+ SubBorder( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 = 0 )
+ {
+ _nodes[0] = n1;
+ _nodes[1] = n2;
+ _nbNodes = bool( n1 ) + bool( n2 );
+ if ( _nbNodes == 2 && n1 > n2 )
+ std::swap( _nodes[0], _nodes[1] );
+ }
+ bool operator<( const SubBorder& other ) const
+ {
+ for ( int i = 0; i < _nbNodes; ++i )
+ {
+ if ( _nodes[i] < other._nodes[i] ) return true;
+ if ( _nodes[i] > other._nodes[i] ) return false;
+ }
+ return false;
+ }
+ };
+
+ //--------------------------------------------------------------------------------
+ // Map a SubBorder to all FissureBorder it bounds
+ struct FissureBorder;
+ typedef std::map< SubBorder, std::vector< FissureBorder* > > TBorderLinks;
+ typedef TBorderLinks::iterator TMappedSub;
+
+ //--------------------------------------------------------------------------------
+ /*!
+ * \brief Element border (volume facet or face edge) at a fissure
+ */
+ struct FissureBorder
+ {
+ std::vector< const SMDS_MeshNode* > _nodes; // border nodes
+ const SMDS_MeshElement* _elems[2]; // volume or face adjacent to fissure
+
+ std::vector< TMappedSub > _mappedSubs; // Sub() in TBorderLinks map
+ std::vector< const SMDS_MeshNode* > _sortedNodes; // to compare FissureBorder's
+
+ FissureBorder( FissureBorder && from ) // move constructor
+ {
+ std::swap( _nodes, from._nodes );
+ std::swap( _sortedNodes, from._sortedNodes );
+ _elems[0] = from._elems[0];
+ _elems[1] = from._elems[1];
+ }
+
+ FissureBorder( const SMDS_MeshElement* elemToDuplicate,
+ std::vector< const SMDS_MeshElement* > & adjElems)
+ : _nodes( elemToDuplicate->NbCornerNodes() )
+ {
+ for ( size_t i = 0; i < _nodes.size(); ++i )
+ _nodes[i] = elemToDuplicate->GetNode( i );
+
+ SMDSAbs_ElementType type = SMDSAbs_ElementType( elemToDuplicate->GetType() + 1 );
+ findAdjacent( type, adjElems );
+ }
+
+ FissureBorder( const SMDS_MeshNode** nodes,
+ const size_t nbNodes,
+ const SMDSAbs_ElementType adjElemsType,
+ std::vector< const SMDS_MeshElement* > & adjElems)
+ : _nodes( nodes, nodes + nbNodes )
+ {
+ findAdjacent( adjElemsType, adjElems );
+ }
+
+ void findAdjacent( const SMDSAbs_ElementType adjElemsType,
+ std::vector< const SMDS_MeshElement* > & adjElems)
+ {
+ _elems[0] = _elems[1] = 0;
+ adjElems.clear();
+ if ( SMDS_Mesh::GetElementsByNodes( _nodes, adjElems, adjElemsType ))
+ for ( size_t i = 0; i < adjElems.size() && i < 2; ++i )
+ _elems[i] = adjElems[i];
+ }
+
+ bool operator<( const FissureBorder& other ) const
+ {
+ return GetSortedNodes() < other.GetSortedNodes();
+ }
+
+ const std::vector< const SMDS_MeshNode* >& GetSortedNodes() const
+ {
+ if ( _sortedNodes.empty() && !_nodes.empty() )
+ {
+ FissureBorder* me = const_cast<FissureBorder*>( this );
+ me->_sortedNodes = me->_nodes;
+ std::sort( me->_sortedNodes.begin(), me->_sortedNodes.end() );
+ }
+ return _sortedNodes;
+ }
+
+ size_t NbSub() const
+ {
+ return _nodes.size();
+ }
+
+ SubBorder Sub(size_t i) const
+ {
+ return SubBorder( _nodes[i], NbSub() > 2 ? _nodes[ (i+1)%NbSub() ] : 0 );
+ }
+
+ void AddSelfTo( TBorderLinks& borderLinks )
+ {
+ _mappedSubs.resize( NbSub() );
+ for ( size_t i = 0; i < NbSub(); ++i )
+ {
+ TBorderLinks::iterator s2b =
+ borderLinks.insert( std::make_pair( Sub(i), TBorderLinks::mapped_type() )).first;
+ s2b->second.push_back( this );
+ _mappedSubs[ i ] = s2b;
+ }
+ }
+
+ void Clear()
+ {
+ _nodes.clear();
+ }
+
+ const SMDS_MeshElement* GetMarkedElem() const
+ {
+ if ( _nodes.empty() ) return 0; // cleared
+ if ( _elems[0] && _elems[0]->isMarked() ) return _elems[0];
+ if ( _elems[1] && _elems[1]->isMarked() ) return _elems[1];
+ return 0;
+ }
+
+ gp_XYZ GetNorm() const // normal to the border
+ {
+ gp_XYZ norm;
+ if ( _nodes.size() == 2 )
+ {
+ gp_XYZ avgNorm( 0,0,0 ); // sum of normals of adjacent faces
+ if ( SMESH_MeshAlgos::FaceNormal( _elems[0], norm ))
+ avgNorm += norm;
+ if ( SMESH_MeshAlgos::FaceNormal( _elems[1], norm ))
+ avgNorm += norm;
+
+ gp_XYZ bordDir( SMESH_NodeXYZ( this->_nodes[0] ) - SMESH_NodeXYZ( this->_nodes[1] ));
+ norm = bordDir ^ avgNorm;
+ }
+ else
+ {
+ SMESH_NodeXYZ p0( _nodes[0] );
+ SMESH_NodeXYZ p1( _nodes[1] );
+ SMESH_NodeXYZ p2( _nodes[2] );
+ norm = ( p0 - p1 ) ^ ( p2 - p1 );
+ }
+ if ( isOut( _nodes[0], norm, GetMarkedElem() ))
+ norm.Reverse();
+
+ return norm;
+ }
+
+ void ChooseSide() // mark an _elem located at positive side of fissure
+ {
+ _elems[0]->setIsMarked( true );
+ gp_XYZ norm = GetNorm();
+ double maxX = norm.Coord(1);
+ if ( Abs( maxX ) < Abs( norm.Coord(2)) ) maxX = norm.Coord(2);
+ if ( Abs( maxX ) < Abs( norm.Coord(3)) ) maxX = norm.Coord(3);
+ if ( maxX < 0 )
+ {
+ _elems[0]->setIsMarked( false );
+ if ( _elems[1] )
+ _elems[1]->setIsMarked( true );
+ }
+ }
+
+ }; // struct FissureBorder
+
+ //--------------------------------------------------------------------------------
+ /*!
+ * \brief Classifier of elements at fissure edge
+ */
+ class FissureNormal
+ {
+ std::vector< gp_XYZ > _normals;
+ bool _bothIn;
+
+ public:
+ void Add( const SMDS_MeshNode* n, const FissureBorder& bord )
+ {
+ _bothIn = false;
+ _normals.reserve(2);
+ _normals.push_back( bord.GetNorm() );
+ if ( _normals.size() == 2 )
+ _bothIn = !isOut( n, _normals[0], bord.GetMarkedElem() );
+ }
+
+ bool IsIn( const SMDS_MeshNode* n, const SMDS_MeshElement* elem ) const
+ {
+ bool isIn = false;
+ switch ( _normals.size() ) {
+ case 1:
+ {
+ isIn = !isOut( n, _normals[0], elem );
+ break;
+ }
+ case 2:
+ {
+ bool in1 = !isOut( n, _normals[0], elem );
+ bool in2 = !isOut( n, _normals[1], elem );
+ isIn = _bothIn ? ( in1 && in2 ) : ( in1 || in2 );
+ }
+ }
+ return isIn;
+ }
+ };
+
+ //================================================================================
+ /*!
+ * \brief Classify an element by a plane passing through a node
+ */
+ //================================================================================
+
+ bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem )
+ {
+ SMESH_NodeXYZ p = n;
+ double sumDot = 0;
+ for ( int i = 0, nb = elem->NbCornerNodes(); i < nb; ++i )
+ {
+ SMESH_NodeXYZ pi = elem->GetNode( i );
+ sumDot += norm * ( pi - p );
+ }
+ return sumDot < -1e-100;
}
- // ====================================================================
- // 3. Replace nodes in elements of the side 1 and remove replaced nodes
- // ====================================================================
+ //================================================================================
+ /*!
+ * \brief Find FissureBorder's by nodes to duplicate
+ */
+ //================================================================================
- // delete temporary faces
-// 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);
+ void findFissureBorders( const TIDSortedElemSet& theNodes,
+ std::vector< FissureBorder > & theFissureBorders )
+ {
+ TIDSortedElemSet::const_iterator nIt = theNodes.begin();
+ const SMDS_MeshNode* n = dynamic_cast< const SMDS_MeshNode*>( *nIt );
+ if ( !n ) return;
+ SMDSAbs_ElementType elemType = SMDSAbs_Volume;
+ if ( n->NbInverseElements( elemType ) == 0 )
+ {
+ elemType = SMDSAbs_Face;
+ if ( n->NbInverseElements( elemType ) == 0 )
+ return;
+ }
+ // unmark elements touching the fissure
+ for ( ; nIt != theNodes.end(); ++nIt )
+ SMESH_MeshAlgos::MarkElems( cast2Node(*nIt)->GetInverseElementIterator(), false );
- if ( aResult != SEW_OK)
- return aResult;
+ // loop on elements touching the fissure to get their borders belonging to the fissure
+ std::set< FissureBorder > fissureBorders;
+ std::vector< const SMDS_MeshElement* > adjElems;
+ std::vector< const SMDS_MeshNode* > nodes;
+ SMDS_VolumeTool volTool;
+ for ( nIt = theNodes.begin(); nIt != theNodes.end(); ++nIt )
+ {
+ SMDS_ElemIteratorPtr invIt = cast2Node(*nIt)->GetInverseElementIterator( elemType );
+ while ( invIt->more() )
+ {
+ const SMDS_MeshElement* eInv = invIt->next();
+ if ( eInv->isMarked() ) continue;
+ eInv->setIsMarked( true );
- 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;
+ if ( elemType == SMDSAbs_Volume )
+ {
+ volTool.Set( eInv );
+ int iQuad = eInv->IsQuadratic() ? 2 : 1;
+ for ( int iF = 0, nbF = volTool.NbFaces(); iF < nbF; ++iF )
+ {
+ const SMDS_MeshNode** nn = volTool.GetFaceNodes( iF );
+ int nbN = volTool.NbFaceNodes( iF ) / iQuad;
+ nodes.clear();
+ bool allOnFissure = true;
+ for ( int iN = 0; iN < nbN && allOnFissure; iN += iQuad )
+ if (( allOnFissure = theNodes.count( nn[ iN ])))
+ nodes.push_back( nn[ iN ]);
+ if ( allOnFissure )
+ fissureBorders.insert( std::move( FissureBorder( &nodes[0], nodes.size(),
+ elemType, adjElems )));
}
- nodes[ i++ ] = n;
}
- // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
- // elemIDsToRemove.push_back( e->GetID() );
- // else
- if ( nbReplaced )
+ else // elemType == SMDSAbs_Face
+ {
+ const SMDS_MeshNode* nn[2] = { eInv->GetNode( eInv->NbCornerNodes()-1 ), 0 };
+ bool onFissure0 = theNodes.count( nn[0] ), onFissure1;
+ for ( int iN = 0, nbN = eInv->NbCornerNodes(); iN < nbN; ++iN )
+ {
+ nn[1] = eInv->GetNode( iN );
+ onFissure1 = theNodes.count( nn[1] );
+ if ( onFissure0 && onFissure1 )
+ fissureBorders.insert( std::move( FissureBorder( nn, 2, elemType, adjElems )));
+ nn[0] = nn[1];
+ onFissure0 = onFissure1;
+ }
+ }
+ }
+ }
+
+ theFissureBorders.reserve( theFissureBorders.size() + fissureBorders.size());
+ std::set< FissureBorder >::iterator bord = fissureBorders.begin();
+ for ( ; bord != fissureBorders.end(); ++bord )
+ {
+ theFissureBorders.push_back( std::move( const_cast<FissureBorder&>( *bord ) ));
+ }
+ return;
+ } // findFissureBorders()
+
+ //================================================================================
+ /*!
+ * \brief Find elements on one side of a fissure defined by elements or nodes to duplicate
+ * \param [in] theElemsOrNodes - elements or nodes to duplicate
+ * \param [in] theNodesNot - nodes not to duplicate
+ * \param [out] theAffectedElems - the found elements
+ */
+ //================================================================================
+
+ void findAffectedElems( const TIDSortedElemSet& theElemsOrNodes,
+ TIDSortedElemSet& theAffectedElems)
+ {
+ if ( theElemsOrNodes.empty() ) return;
+
+ // find FissureBorder's
+
+ std::vector< FissureBorder > fissure;
+ std::vector< const SMDS_MeshElement* > elemsByFacet;
+
+ TIDSortedElemSet::const_iterator elIt = theElemsOrNodes.begin();
+ if ( (*elIt)->GetType() == SMDSAbs_Node )
+ {
+ findFissureBorders( theElemsOrNodes, fissure );
+ }
+ else
+ {
+ fissure.reserve( theElemsOrNodes.size() );
+ for ( ; elIt != theElemsOrNodes.end(); ++elIt )
+ {
+ fissure.push_back( std::move( FissureBorder( *elIt, elemsByFacet )));
+ if ( !fissure.back()._elems[1] )
+ fissure.pop_back();
+ }
+ }
+ if ( fissure.empty() )
+ return;
+
+ // fill borderLinks
+
+ TBorderLinks borderLinks;
+
+ for ( size_t i = 0; i < fissure.size(); ++i )
+ {
+ fissure[i].AddSelfTo( borderLinks );
+ }
+
+ // get theAffectedElems
+
+ // unmark elements having nodes on the fissure, theAffectedElems elements will be marked
+ for ( size_t i = 0; i < fissure.size(); ++i )
+ for ( size_t j = 0; j < fissure[i]._nodes.size(); ++j )
+ {
+ SMESH_MeshAlgos::MarkElemNodes( fissure[i]._nodes[j]->GetInverseElementIterator(),
+ false, /*markElem=*/true );
+ }
+
+ std::vector<const SMDS_MeshNode *> facetNodes;
+ std::map< const SMDS_MeshNode*, FissureNormal > fissEdgeNodes2Norm;
+ boost::container::flat_set< const SMDS_MeshNode* > fissureNodes;
+
+ // choose a side of fissure
+ fissure[0].ChooseSide();
+ theAffectedElems.insert( fissure[0].GetMarkedElem() );
+
+ size_t nbCheckedBorders = 0;
+ while ( nbCheckedBorders < fissure.size() )
+ {
+ // find a FissureBorder to treat
+ FissureBorder* bord = 0;
+ for ( size_t i = 0; i < fissure.size() && !bord; ++i )
+ if ( fissure[i].GetMarkedElem() )
+ bord = & fissure[i];
+ for ( size_t i = 0; i < fissure.size() && !bord; ++i )
+ if ( fissure[i].NbSub() > 0 && fissure[i]._elems[0] )
+ {
+ bord = & fissure[i];
+ bord->ChooseSide();
+ theAffectedElems.insert( bord->GetMarkedElem() );
+ }
+ if ( !bord ) return;
+ ++nbCheckedBorders;
+
+ // treat FissureBorder's linked to bord
+ fissureNodes.clear();
+ fissureNodes.insert( bord->_nodes.begin(), bord->_nodes.end() );
+ for ( size_t i = 0; i < bord->NbSub(); ++i )
+ {
+ TBorderLinks::iterator l2b = bord->_mappedSubs[ i ];
+ if ( l2b == borderLinks.end() || l2b->second.empty() ) continue;
+ std::vector< FissureBorder* >& linkedBorders = l2b->second;
+ const SubBorder& sb = l2b->first;
+ const SMDS_MeshElement* bordElem = bord->GetMarkedElem();
+
+ if ( linkedBorders.size() == 1 ) // fissure edge reached, fill fissEdgeNodes2Norm
+ {
+ for ( int j = 0; j < sb._nbNodes; ++j )
+ fissEdgeNodes2Norm[ sb._nodes[j] ].Add( sb._nodes[j], *bord );
+ continue;
+ }
+
+ // add to theAffectedElems elems sharing nodes of a SubBorder and a node of bordElem
+ // until an elem adjacent to a neighbour FissureBorder is found
+ facetNodes.clear();
+ facetNodes.insert( facetNodes.end(), sb._nodes, sb._nodes + sb._nbNodes );
+ facetNodes.resize( sb._nbNodes + 1 );
+
+ while ( bordElem )
+ {
+ // check if bordElem is adjacent to a neighbour FissureBorder
+ for ( size_t j = 0; j < linkedBorders.size(); ++j )
{
- 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);
+ FissureBorder* bord2 = linkedBorders[j];
+ if ( bord2 == bord ) continue;
+ if ( bordElem == bord2->_elems[0] || bordElem == bord2->_elems[1] )
+ bordElem = 0;
+ else
+ fissureNodes.insert( bord2->_nodes.begin(), bord2->_nodes.end() );
}
- }
- }
+ if ( !bordElem )
+ break;
- Remove( nodeIDsToRemove, true );
+ // find the next bordElem
+ const SMDS_MeshElement* nextBordElem = 0;
+ for ( int iN = 0, nbN = bordElem->NbCornerNodes(); iN < nbN && !nextBordElem; ++iN )
+ {
+ const SMDS_MeshNode* n = bordElem->GetNode( iN );
+ if ( fissureNodes.count( n )) continue;
- return aResult;
-}
+ facetNodes[ sb._nbNodes ] = n;
+ elemsByFacet.clear();
+ if ( SMDS_Mesh::GetElementsByNodes( facetNodes, elemsByFacet ) > 1 )
+ {
+ for ( size_t iE = 0; iE < elemsByFacet.size(); ++iE )
+ if ( elemsByFacet[ iE ] != bordElem &&
+ !elemsByFacet[ iE ]->isMarked() )
+ {
+ theAffectedElems.insert( elemsByFacet[ iE ]);
+ elemsByFacet[ iE ]->setIsMarked( true );
+ if ( elemsByFacet[ iE ]->GetType() == bordElem->GetType() )
+ nextBordElem = elemsByFacet[ iE ];
+ }
+ }
+ }
+ bordElem = nextBordElem;
-//================================================================================
-/*!
- * \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
- * \return bool - is a success or not
- */
-//================================================================================
+ } // while ( bordElem )
-#ifdef _DEBUG_
-//#define DEBUG_MATCHING_NODES
-#endif
+ linkedBorders.clear(); // not to treat this link any more
-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 };
+ } // loop on SubBorder's of a FissureBorder
- nReplaceMap.clear();
- if ( theFirstNode1 != theFirstNode2 )
- nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
- if ( theSecondNode1 != theSecondNode2 )
- nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
+ bord->Clear();
- set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
- linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
+ } // loop on FissureBorder's
- 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;
+ // add elements sharing only one node of the fissure, except those sharing fissure edge nodes
- // 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
- // ---------------------------------------------------------------
+ // mark nodes of theAffectedElems
+ SMESH_MeshAlgos::MarkElemNodes( theAffectedElems.begin(), theAffectedElems.end(), true );
- 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
+ // unmark nodes of the fissure
+ elIt = theElemsOrNodes.begin();
+ if ( (*elIt)->GetType() == SMDSAbs_Node )
+ SMESH_MeshAlgos::MarkElems( elIt, theElemsOrNodes.end(), false );
+ else
+ SMESH_MeshAlgos::MarkElemNodes( elIt, theElemsOrNodes.end(), false );
+
+ std::vector< gp_XYZ > normVec;
+
+ // loop on nodes of the fissure, add elements having marked nodes
+ for ( elIt = theElemsOrNodes.begin(); elIt != theElemsOrNodes.end(); ++elIt )
{
- 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
+ const SMDS_MeshElement* e = (*elIt);
+ if ( e->GetType() != SMDSAbs_Node )
+ e->setIsMarked( true ); // avoid adding a fissure element
+
+ for ( int iN = 0, nbN = e->NbCornerNodes(); iN < nbN; ++iN )
{
- // 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 );
+ const SMDS_MeshNode* n = e->GetNode( iN );
+ if ( fissEdgeNodes2Norm.count( n ))
+ continue;
- // 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 ) );
+ SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
+ while ( invIt->more() )
+ {
+ const SMDS_MeshElement* eInv = invIt->next();
+ if ( eInv->isMarked() ) continue;
+ eInv->setIsMarked( true );
+
+ SMDS_ElemIteratorPtr nIt = eInv->nodesIterator();
+ while( nIt->more() )
+ if ( nIt->next()->isMarked())
+ {
+ theAffectedElems.insert( eInv );
+ SMESH_MeshAlgos::MarkElems( eInv->nodesIterator(), true );
+ n->setIsMarked( false );
+ break;
}
- }
}
}
}
- // 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
- // -------------------
+ // add elements on the fissure edge
+ std::map< const SMDS_MeshNode*, FissureNormal >::iterator n2N;
+ for ( n2N = fissEdgeNodes2Norm.begin(); n2N != fissEdgeNodes2Norm.end(); ++n2N )
+ {
+ const SMDS_MeshNode* edgeNode = n2N->first;
+ const FissureNormal & normals = n2N->second;
- 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];
+ SMDS_ElemIteratorPtr invIt = edgeNode->GetInverseElementIterator();
+ while ( invIt->more() )
{
- 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++) ));
+ const SMDS_MeshElement* eInv = invIt->next();
+ if ( eInv->isMarked() ) continue;
+ eInv->setIsMarked( true );
+
+ // classify eInv using normals
+ bool toAdd = normals.IsIn( edgeNode, eInv );
+ if ( toAdd ) // check if all nodes lie on the fissure edge
+ {
+ bool notOnEdge = false;
+ for ( int iN = 0, nbN = eInv->NbCornerNodes(); iN < nbN && !notOnEdge; ++iN )
+ notOnEdge = !fissEdgeNodes2Norm.count( eInv->GetNode( iN ));
+ toAdd = notOnEdge;
+ }
+ if ( toAdd )
+ {
+ theAffectedElems.insert( eInv );
}
}
+ }
- // add other links of the face 1 to linkList
- // -----------------------------------------
+ return;
+ } // findAffectedElems()
+} // namespace
- const SMDS_MeshElement* f0 = face[0];
- const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
- for ( int i = 0; i < nbN; i++ )
+//================================================================================
+/*!
+ * \brief Create elements equal (on same nodes) to given ones
+ * \param [in] theElements - a set of elems to duplicate. If it is empty, all
+ * elements of the uppest dimension are duplicated.
+ */
+//================================================================================
+
+void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
+{
+ ClearLastCreated();
+ SMESHDS_Mesh* mesh = GetMeshDS();
+
+ // get an element type and an iterator over elements
+
+ SMDSAbs_ElementType type = SMDSAbs_All;
+ SMDS_ElemIteratorPtr elemIt;
+ if ( theElements.empty() )
+ {
+ if ( mesh->NbNodes() == 0 )
+ return;
+ // get most complex type
+ SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
+ SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
+ SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
+ };
+ for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
+ if ( mesh->GetMeshInfo().NbElements( types[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;
+ type = types[i];
+ elemIt = mesh->elementsIterator( type );
+ break;
}
- } // 2 faces found
- } // loop on link lists
+ }
+ else
+ {
+ //type = (*theElements.begin())->GetType();
+ elemIt = SMESHUtils::elemSetIterator( theElements );
+ }
- return SEW_OK;
+ // un-mark all elements to avoid duplicating just created elements
+ SMESH_MeshAlgos::MarkElems( mesh->elementsIterator( type ), false );
+
+ // duplicate elements
+
+ ElemFeatures elemType;
+
+ vector< const SMDS_MeshNode* > nodes;
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* elem = elemIt->next();
+ if (( type != SMDSAbs_All && elem->GetType() != type ) ||
+ ( elem->isMarked() ))
+ continue;
+
+ elemType.Init( elem, /*basicOnly=*/false );
+ nodes.assign( elem->begin_nodes(), elem->end_nodes() );
+
+ if ( const SMDS_MeshElement* newElem = AddElement( nodes, elemType ))
+ newElem->setIsMarked( true );
+ }
}
//================================================================================
const TIDSortedElemSet& theNodesNot,
const TIDSortedElemSet& theAffectedElems )
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ ClearLastCreated();
if ( theElems.size() == 0 )
return false;
return false;
bool res = false;
- std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+ TNodeNodeMap anOldNodeToNewNode;
// duplicate elements and nodes
res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
// replce nodes by duplications
*/
//================================================================================
-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 )
+bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh* theMeshDS,
+ const TIDSortedElemSet& theElems,
+ const TIDSortedElemSet& theNodesNot,
+ TNodeNodeMap& theNodeNodeMap,
+ const bool theIsDoubleElem )
{
- MESSAGE("doubleNodes");
- // iterate on through element and duplicate them (by nodes duplication)
+ // iterate through element and duplicate them (by nodes duplication)
bool res = false;
+ std::vector<const SMDS_MeshNode*> newNodes;
+ ElemFeatures elemType;
+
TIDSortedElemSet::const_iterator elemItr = theElems.begin();
for ( ; elemItr != theElems.end(); ++elemItr )
{
const SMDS_MeshElement* anElem = *elemItr;
- if (!anElem)
- continue;
+ // if (!anElem)
+ // continue;
- bool isDuplicate = false;
// duplicate nodes to duplicate element
- std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
+ bool isDuplicate = false;
+ newNodes.resize( 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() )
+ const SMDS_MeshNode* aCurrNode = static_cast<const SMDS_MeshNode*>( anIter->next() );
+ const SMDS_MeshNode* aNewNode = aCurrNode;
+ TNodeNodeMap::iterator n2n = theNodeNodeMap.find( aCurrNode );
+ if ( n2n != theNodeNodeMap.end() )
+ {
+ aNewNode = n2n->second;
+ }
+ else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode ))
{
// duplicate node
aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
+ copyPosition( aCurrNode, aNewNode );
theNodeNodeMap[ aCurrNode ] = aNewNode;
- myLastCreatedNodes.Append( aNewNode );
+ myLastCreatedNodes.push_back( aNewNode );
}
isDuplicate |= (aCurrNode != aNewNode);
newNodes[ ind++ ] = aNewNode;
continue;
if ( theIsDoubleElem )
- AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
+ AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false ));
else
- {
- MESSAGE("ChangeElementNodes");
- theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
- }
+ theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() );
+
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
+ 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();
+ ClearLastCreated();
if ( theListOfNodes.size() == 0 )
return false;
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 );
+ const SMDS_MeshNode* aNode = aMeshDS->FindNode( *aNodeIter );
if ( !aNode )
continue;
const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
if ( aNewNode )
{
+ copyPosition( aNode, 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;
- }
- else
- aNodeArr[ ind++ ] = aCurrNode;
+ myLastCreatedNodes.push_back( aNewNode );
}
- anElemToNodes[ anElem ] = aNodeArr;
}
// Change nodes of elements
- std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
- anElemToNodesIter = anElemToNodes.begin();
- for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
+ std::vector<const SMDS_MeshNode*> aNodeArr;
+
+ std::list< int >::const_iterator anElemIter;
+ for ( anElemIter = theListOfModifiedElems.begin();
+ anElemIter != theListOfModifiedElems.end();
+ anElemIter++ )
{
- const SMDS_MeshElement* anElem = anElemToNodesIter->first;
- vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
- if ( anElem )
- {
- MESSAGE("ChangeElementNodes");
- aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
- }
+ const SMDS_MeshElement* anElem = aMeshDS->FindElement( *anElemIter );
+ if ( !anElem )
+ continue;
+
+ aNodeArr.assign( anElem->begin_nodes(), anElem->end_nodes() );
+ for( size_t i = 0; i < aNodeArr.size(); ++i )
+ {
+ std::map< const SMDS_MeshNode*, const SMDS_MeshNode* >::iterator n2n =
+ anOldNodeToNewNode.find( aNodeArr[ i ]);
+ if ( n2n != anOldNodeToNewNode.end() )
+ aNodeArr[ i ] = n2n->second;
+ }
+ aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], aNodeArr.size() );
}
return true;
//================================================================================
/*!
- \brief Check if element located inside shape
- \return TRUE if IN or ON shape, FALSE otherwise
+ \brief Check if element located inside shape
+ \return TRUE if IN or ON shape, FALSE otherwise
*/
//================================================================================
const double theTol)
{
gp_XYZ centerXYZ (0, 0, 0);
- SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
- while (aNodeItr->more())
- centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
+ for ( SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator(); aNodeItr->more(); )
+ centerXYZ += SMESH_NodeXYZ( aNodeItr->next() );
gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
theClassifier.Perform(aPnt, theTol);
}
void Perform(const gp_Pnt& aPnt, double theTol)
{
+ theTol *= theTol;
_state = TopAbs_OUT;
_extremum.Perform(aPnt);
if ( _extremum.IsDone() )
for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
-#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
_state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
-#else
- _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
-#endif
}
TopAbs_State State() const
{
//================================================================================
/*!
- \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
+ \brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
This method is the first step of DoubleNodeElemGroupsInRegion.
\param theElems - list of groups of elements (edges or faces) to be replicated
- \param theNodesNot - list of groups of nodes not to replicated
+ \param theNodesNot - list of groups of nodes not to replicate
\param theShape - shape to detect affected elements (element which geometric center
- located on or inside shape).
+ located on or inside shape). If the shape is null, detection is done on faces orientations
+ (select elements with a gravity center on the side given by faces normals).
+ This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations.
The replicated nodes should be associated to affected elements.
- \return groups of affected elements
+ \return true
\sa DoubleNodeElemGroupsInRegion()
- */
+*/
//================================================================================
bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
TIDSortedElemSet& theAffectedElems)
{
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)));
+ findAffectedElems( theElems, theAffectedElems );
}
-
- // iterates on indicated elements and get elements by back references from their nodes
- TIDSortedElemSet::const_iterator elemItr = theElems.begin();
- for ( ; elemItr != theElems.end(); ++elemItr )
+ else
{
- SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
- if (!anElem)
- continue;
+ const double aTol = Precision::Confusion();
+ std::unique_ptr< BRepClass3d_SolidClassifier> bsc3d;
+ std::unique_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)));
+ }
- SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
- while ( nodeItr->more() )
+ // iterates on indicated elements and get elements by back references from their nodes
+ TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+ for ( ; elemItr != theElems.end(); ++elemItr )
{
- const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
- if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
- continue;
- SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
- while ( backElemItr->more() )
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+ SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+ while ( nodeItr->more() )
{
- const SMDS_MeshElement* curElem = backElemItr->next();
- if ( curElem && theElems.find(curElem) == theElems.end() &&
- ( bsc3d.get() ?
- isInside( curElem, *bsc3d, aTol ) :
- isInside( curElem, *aFaceClassifier, aTol )))
- theAffectedElems.insert( curElem );
+ 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 )))
+ theAffectedElems.insert( curElem );
+ }
}
}
}
return false;
const double aTol = Precision::Confusion();
- auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
- auto_ptr<_FaceClassifier> aFaceClassifier;
+ SMESHUtils::Deleter< BRepClass3d_SolidClassifier> bsc3d;
+ SMESHUtils::Deleter<_FaceClassifier> aFaceClassifier;
if ( theShape.ShapeType() == TopAbs_SOLID )
{
- bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
+ bsc3d._obj = new BRepClass3d_SolidClassifier( theShape );
bsc3d->PerformInfinitePoint(aTol);
}
else if (theShape.ShapeType() == TopAbs_FACE )
{
- aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
+ aFaceClassifier._obj = new _FaceClassifier( TopoDS::Face( theShape ));
}
// iterates on indicated elements and get elements by back references from their nodes
{
const SMDS_MeshElement* curElem = backElemItr->next();
if ( curElem && theElems.find(curElem) == theElems.end() &&
- ( bsc3d.get() ?
+ ( bsc3d ?
isInside( curElem, *bsc3d, aTol ) :
isInside( curElem, *aFaceClassifier, aTol )))
anAffected.insert( curElem );
*/
double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
{
-// MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
-// MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
-// MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
-// MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
gp_Vec vref(p0, p1);
gp_Vec v1(p0, g1);
gp_Vec v2(p0, g2);
gp_Vec n1 = vref.Crossed(v1);
gp_Vec n2 = vref.Crossed(v2);
- return n2.AngleWithRef(n1, vref);
+ try {
+ return n2.AngleWithRef(n1, vref);
+ }
+ catch ( Standard_Failure& ) {
+ }
+ return Max( v1.Magnitude(), v2.Magnitude() );
}
/*!
* If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created.
* All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
* The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
- * @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
+ * \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
+ * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
+ * the boundary between \a theDomains and the rest mesh
+ * \return TRUE if operation has been completed successfully, FALSE otherwise
*/
bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
- bool createJointElems)
+ bool createJointElems,
+ bool onAllBoundaries)
{
- MESSAGE("----------------------------------------------");
- MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
- MESSAGE("----------------------------------------------");
+ // MESSAGE("----------------------------------------------");
+ // MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
+ // MESSAGE("----------------------------------------------");
SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
meshDS->BuildDownWardConnectivity(true);
CHRONO(50);
- SMDS_UnstructuredGrid *grid = meshDS->getGrid();
+ 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 cells with only a node or an edge on the border, with their domain and volume indexes
std::set<int> emptySet;
emptyMap.clear();
- MESSAGE(".. Number of domains :"<<theElems.size());
+ //MESSAGE(".. Number of domains :"<<theElems.size());
+
+ TIDSortedElemSet theRestDomElems;
+ const int iRestDom = -1;
+ const int idom0 = onAllBoundaries ? iRestDom : 0;
+ const int nbDomains = theElems.size();
// Check if the domains do not share an element
- for (int idom = 0; idom < theElems.size()-1; idom++)
- {
-// MESSAGE("... Check of domain #" << idom);
- const TIDSortedElemSet& domain = theElems[idom];
- TIDSortedElemSet::const_iterator elemItr = domain.begin();
- for (; elemItr != domain.end(); ++elemItr)
+ for (int idom = 0; idom < nbDomains-1; idom++)
+ {
+ // MESSAGE("... Check of domain #" << idom);
+ const TIDSortedElemSet& domain = theElems[idom];
+ TIDSortedElemSet::const_iterator elemItr = domain.begin();
+ for (; elemItr != domain.end(); ++elemItr)
+ {
+ const SMDS_MeshElement* anElem = *elemItr;
+ int idombisdeb = idom + 1 ;
+ // check if the element belongs to a domain further in the list
+ for ( size_t idombis = idombisdeb; idombis < theElems.size(); idombis++ )
+ {
+ const TIDSortedElemSet& domainbis = theElems[idombis];
+ if ( domainbis.count( anElem ))
{
- SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
- int idombisdeb = idom + 1 ;
- for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
- {
- const TIDSortedElemSet& domainbis = theElems[idombis];
- if ( domainbis.count(anElem) )
- {
- MESSAGE(".... Domain #" << idom);
- MESSAGE(".... Domain #" << idombis);
- throw SALOME_Exception("The domains are not disjoint.");
- return false ;
- }
- }
+ MESSAGE(".... Domain #" << idom);
+ MESSAGE(".... Domain #" << idombis);
+ throw SALOME_Exception("The domains are not disjoint.");
+ return false ;
}
+ }
}
+ }
- for (int idom = 0; idom < theElems.size(); idom++)
- {
+ for (int idom = 0; idom < nbDomains; 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 his domain.
+ // --- 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 his domain.
- MESSAGE("... Neighbors of domain #" << idom);
- const TIDSortedElemSet& domain = theElems[idom];
- TIDSortedElemSet::const_iterator elemItr = domain.begin();
- for (; elemItr != domain.end(); ++elemItr)
+ //MESSAGE("... Neighbors of domain #" << idom);
+ const TIDSortedElemSet& domain = theElems[idom];
+ TIDSortedElemSet::const_iterator elemItr = domain.begin();
+ for (; elemItr != domain.end(); ++elemItr)
+ {
+ const SMDS_MeshElement* anElem = *elemItr;
+ if (!anElem)
+ continue;
+ vtkIdType vtkId = anElem->GetVtkID();
+ //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID());
+ 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++)
+ {
+ smIdType smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
+ const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
+ if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared
{
- SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
- if (!anElem)
- continue;
- int vtkId = anElem->getVtkId();
- //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID());
- 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++)
+ bool ok = false;
+ for ( size_t idombis = 0; idombis < theElems.size() && !ok; idombis++) // check if the neighbor belongs to another domain of the list
+ {
+ // MESSAGE("Domain " << idombis);
+ const TIDSortedElemSet& domainbis = theElems[idombis];
+ if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
+ }
+ if ( ok || onAllBoundaries ) // the characteristics of the face is stored
+ {
+ DownIdType face(downIds[n], downTypes[n]);
+ if (!faceDomains[face].count(idom))
{
- 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
- {
- bool ok = false ;
- for (int idombis = 0; idombis < theElems.size(); idombis++) // check if the neighbor belongs to another domain of the list
- {
- // MESSAGE("Domain " << idombis);
- const TIDSortedElemSet& domainbis = theElems[idombis];
- if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
- }
- if ( ok ) // the characteristics of the face is stored
- {
- 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
- celldom[vtkId] = idom;
- //MESSAGE(" cell with a border " << vtkId << " domain " << idom);
- }
- }
- }
+ faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+ celldom[vtkId] = idom;
+ //MESSAGE(" cell with a border " << vtkId << " domain " << idom);
+ }
+ if ( !ok )
+ {
+ theRestDomElems.insert( elem );
+ faceDomains[face][iRestDom] = neighborsVtkIds[n];
+ celldom[neighborsVtkIds[n]] = iRestDom;
}
+ }
}
+ }
}
+ }
//MESSAGE("Number of shared faces " << faceDomains.size());
std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
// explore the nodes of the face and see if they belong to a cell in the domain,
// which has only a node or an edge on the border (not a shared face)
- for (int idomain = 0; idomain < theElems.size(); idomain++)
+ for (int idomain = idom0; idomain < nbDomains; idomain++)
+ {
+ //MESSAGE("Domain " << idomain);
+ const TIDSortedElemSet& domain = (idomain == iRestDom) ? theRestDomElems : theElems[idomain];
+ itface = faceDomains.begin();
+ for (; itface != faceDomains.end(); ++itface)
{
- //MESSAGE("Domain " << idomain);
- const TIDSortedElemSet& domain = theElems[idomain];
- itface = faceDomains.begin();
- for (; itface != faceDomains.end(); ++itface)
+ const std::map<int, int>& domvol = itface->second;
+ if (!domvol.count(idomain))
+ continue;
+ DownIdType face = itface->first;
+ //MESSAGE(" --- face " << face.cellId);
+ 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;
+ //MESSAGE(" node " << oldId);
+ vtkCellLinks::Link l = (static_cast <vtkCellLinks *>(grid->GetCellLinks()))->GetLink(oldId);
+ for (int i=0; i<l.ncells; i++)
{
- std::map<int, int> domvol = itface->second;
- if (!domvol.count(idomain))
+ int vtkId = l.cells[i];
+ const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->FromVtkToSmds(vtkId));
+ if (!domain.count(anElem))
continue;
- DownIdType face = itface->first;
- //MESSAGE(" --- face " << face.cellId);
- 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;
- //MESSAGE(" node " << oldId);
- vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
- for (int i=0; i<l.ncells; i++)
- {
- int vtkId = l.cells[i];
- const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
- if (!domain.count(anElem))
- continue;
- int vtkType = grid->GetCellType(vtkId);
- int downId = grid->CellIdToDownId(vtkId);
- if (downId < 0)
- {
- MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
- continue; // not OK at this stage of the algorithm:
- //no cells created after BuildDownWardConnectivity
- }
- DownIdType aCell(downId, vtkType);
- if (!cellDomains.count(aCell))
- cellDomains[aCell] = emptyMap; // create an empty entry for cell
- cellDomains[aCell][idomain] = vtkId;
- celldom[vtkId] = idomain;
- //MESSAGE(" cell " << vtkId << " domain " << idomain);
- }
- }
+ int vtkType = grid->GetCellType(vtkId);
+ int downId = grid->CellIdToDownId(vtkId);
+ if (downId < 0)
+ {
+ MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
+ continue; // not OK at this stage of the algorithm:
+ //no cells created after BuildDownWardConnectivity
+ }
+ DownIdType aCell(downId, vtkType);
+ cellDomains[aCell][idomain] = vtkId;
+ celldom[vtkId] = idomain;
+ //MESSAGE(" cell " << vtkId << " domain " << idomain);
}
+ }
}
+ }
// --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
// for each shared face, get the nodes
std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
- MESSAGE(".. Duplication of the nodes");
- for (int idomain = 0; idomain < theElems.size(); idomain++)
+ //MESSAGE(".. Duplication of the nodes");
+ for (int idomain = idom0; idomain < nbDomains; idomain++)
+ {
+ itface = faceDomains.begin();
+ for (; itface != faceDomains.end(); ++itface)
{
- itface = faceDomains.begin();
- for (; itface != faceDomains.end(); ++itface)
+ const std::map<int, int>& domvol = itface->second;
+ if (!domvol.count(idomain))
+ continue;
+ DownIdType face = itface->first;
+ //MESSAGE(" --- face " << face.cellId);
+ 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[oldId].empty())
{
- std::map<int, int> domvol = itface->second;
- if (!domvol.count(idomain))
- continue;
- DownIdType face = itface->first;
- //MESSAGE(" --- face " << face.cellId);
- 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)
+ nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
+ //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain);
+ }
+ std::map<int, int>::const_iterator itdom = domvol.begin();
+ for (; itdom != domvol.end(); ++itdom)
+ {
+ int idom = itdom->first;
+ //MESSAGE(" domain " << idom);
+ if (!nodeDomains[oldId].count(idom)) // --- node to clone
+ {
+ if (nodeDomains[oldId].size() >= 2) // a multiple node
{
- int oldId = *itn;
- //MESSAGE("-+-+-a node " << oldId);
- if (!nodeDomains.count(oldId))
- nodeDomains[oldId] = emptyMap; // create an empty entry for node
- if (nodeDomains[oldId].empty())
- {
- nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
- //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain);
- }
- std::map<int, int>::iterator itdom = domvol.begin();
- for (; itdom != domvol.end(); ++itdom)
- {
- int idom = itdom->first;
- //MESSAGE(" domain " << idom);
- if (!nodeDomains[oldId].count(idom)) // --- node to clone
- {
- if (nodeDomains[oldId].size() >= 2) // a multiple node
- {
- vector<int> orderedDoms;
- //MESSAGE("multiple node " << oldId);
- if (mutipleNodes.count(oldId))
- orderedDoms = mutipleNodes[oldId];
- else
- {
- map<int,int>::iterator it = nodeDomains[oldId].begin();
- for (; it != nodeDomains[oldId].end(); ++it)
- orderedDoms.push_back(it->first);
- }
- orderedDoms.push_back(idom); // TODO order ==> push_front or back
- //stringstream txt;
- //for (int i=0; i<orderedDoms.size(); i++)
- // txt << orderedDoms[i] << " ";
- //MESSAGE("orderedDoms " << txt.str());
- mutipleNodes[oldId] = orderedDoms;
- }
- 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
- //MESSAGE("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
- }
- }
+ vector<int> orderedDoms;
+ //MESSAGE("multiple node " << oldId);
+ if (mutipleNodes.count(oldId))
+ orderedDoms = mutipleNodes[oldId];
+ else
+ {
+ map<int,int>::iterator it = nodeDomains[oldId].begin();
+ for (; it != nodeDomains[oldId].end(); ++it)
+ orderedDoms.push_back(it->first);
+ }
+ orderedDoms.push_back(idom); // TODO order ==> push_front or back
+ //stringstream txt;
+ //for (int i=0; i<orderedDoms.size(); i++)
+ // txt << orderedDoms[i] << " ";
+ //MESSAGE("orderedDoms " << txt.str());
+ mutipleNodes[oldId] = orderedDoms;
}
+ double *coords = grid->GetPoint(oldId);
+ SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
+ copyPosition( meshDS->FindNodeVtk( oldId ), newNode );
+ int newId = newNode->GetVtkID();
+ nodeDomains[oldId][idom] = newId; // cloned node for other domains
+ //MESSAGE("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
+ }
}
+ }
}
+ }
- MESSAGE(".. Creation of elements");
- for (int idomain = 0; idomain < theElems.size(); idomain++)
+ //MESSAGE(".. Creation of elements");
+ for (int idomain = idom0; idomain < nbDomains; idomain++)
+ {
+ itface = faceDomains.begin();
+ for (; itface != faceDomains.end(); ++itface)
{
- itface = faceDomains.begin();
- for (; itface != faceDomains.end(); ++itface)
+ std::map<int, int> domvol = itface->second;
+ if (!domvol.count(idomain))
+ continue;
+ DownIdType face = itface->first;
+ //MESSAGE(" --- face " << face.cellId);
+ std::set<int> oldNodes;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ int nbMultipleNodes = 0;
+ std::set<int>::iterator itn = oldNodes.begin();
+ for (; itn != oldNodes.end(); ++itn)
+ {
+ int oldId = *itn;
+ if (mutipleNodes.count(oldId))
+ nbMultipleNodes++;
+ }
+ if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
+ {
+ //MESSAGE("multiple Nodes detected on a shared face");
+ int downId = itface->first.cellId;
+ unsigned char cellType = itface->first.cellType;
+ // --- shared edge or shared face ?
+ if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
{
- std::map<int, int> domvol = itface->second;
- if (!domvol.count(idomain))
- continue;
- DownIdType face = itface->first;
- //MESSAGE(" --- face " << face.cellId);
- std::set<int> oldNodes;
- oldNodes.clear();
- grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
- int nbMultipleNodes = 0;
- std::set<int>::iterator itn = oldNodes.begin();
- for (; itn != oldNodes.end(); ++itn)
- {
- int oldId = *itn;
- if (mutipleNodes.count(oldId))
- nbMultipleNodes++;
- }
- if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
+ int nodes[3];
+ int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
+ for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
+ if (mutipleNodes.count(nodes[i]))
+ if (!mutipleNodesToFace.count(nodes[i]))
+ mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
+ }
+ else // shared face (between two volumes)
+ {
+ int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
+ const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
+ const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
+ for (int ie =0; ie < nbEdges; ie++)
+ {
+ int nodes[3];
+ int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
+ if ( mutipleNodes.count(nodes[0]) && mutipleNodes.count( nodes[ nbNodes-1 ]))
{
- //MESSAGE("multiple Nodes detected on a shared face");
- int downId = itface->first.cellId;
- unsigned char cellType = itface->first.cellType;
- // --- shared edge or shared face ?
- if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
- {
- int nodes[3];
- int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
- for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
- if (mutipleNodes.count(nodes[i]))
- if (!mutipleNodesToFace.count(nodes[i]))
- mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
- }
- else // shared face (between two volumes)
+ vector<int> vn0 = mutipleNodes[nodes[0]];
+ vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
+ vector<int> doms;
+ for ( size_t i0 = 0; i0 < vn0.size(); i0++ )
+ for ( size_t i1 = 0; i1 < vn1.size(); i1++ )
+ if ( vn0[i0] == vn1[i1] )
+ doms.push_back( vn0[ i0 ]);
+ if ( doms.size() > 2 )
+ {
+ //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
+ double *coords = grid->GetPoint(nodes[0]);
+ gp_Pnt p0(coords[0], coords[1], coords[2]);
+ coords = grid->GetPoint(nodes[nbNodes - 1]);
+ gp_Pnt p1(coords[0], coords[1], coords[2]);
+ gp_Pnt gref;
+ int vtkVolIds[1000]; // an edge can belong to a lot of volumes
+ map<int, SMDS_MeshVolume*> domvol; // domain --> a volume with the edge
+ map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
+ int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
+ for ( size_t id = 0; id < doms.size(); id++ )
{
- int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
- const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
- const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
- for (int ie =0; ie < nbEdges; ie++)
+ int idom = doms[id];
+ const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom];
+ for ( int ivol = 0; ivol < nbvol; ivol++ )
+ {
+ smIdType smdsId = meshDS->FromVtkToSmds(vtkVolIds[ivol]);
+ const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
+ if (domain.count(elem))
{
- int nodes[3];
- int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
- if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
- {
- vector<int> vn0 = mutipleNodes[nodes[0]];
- vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
- vector<int> doms;
- for (int i0 = 0; i0 < vn0.size(); i0++)
- for (int i1 = 0; i1 < vn1.size(); i1++)
- if (vn0[i0] == vn1[i1])
- doms.push_back(vn0[i0]);
- if (doms.size() >2)
- {
- //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
- double *coords = grid->GetPoint(nodes[0]);
- gp_Pnt p0(coords[0], coords[1], coords[2]);
- coords = grid->GetPoint(nodes[nbNodes - 1]);
- gp_Pnt p1(coords[0], coords[1], coords[2]);
- gp_Pnt gref;
- int vtkVolIds[1000]; // an edge can belong to a lot of volumes
- map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
- map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
- int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
- for (int id=0; id < doms.size(); id++)
- {
- int idom = doms[id];
- for (int ivol=0; ivol<nbvol; ivol++)
- {
- int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
- SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
- if (theElems[idom].count(elem))
- {
- SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
- domvol[idom] = svol;
- //MESSAGE(" domain " << idom << " volume " << elem->GetID());
- double values[3];
- vtkIdType npts = 0;
- vtkIdType* pts = 0;
- grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
- SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
- if (id ==0)
- {
- gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
- angleDom[idom] = 0;
- }
- else
- {
- gp_Pnt g(values[0], values[1], values[2]);
- angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
- //MESSAGE(" angle=" << angleDom[idom]);
- }
- break;
- }
- }
- }
- map<double, int> sortedDom; // sort domains by angle
- for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
- sortedDom[ia->second] = ia->first;
- vector<int> vnodes;
- vector<int> vdom;
- for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
- {
- vdom.push_back(ib->second);
- //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
- }
- for (int ino = 0; ino < nbNodes; ino++)
- vnodes.push_back(nodes[ino]);
- edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
- }
- }
+ const SMDS_MeshVolume* svol = SMDS_Mesh::DownCast<SMDS_MeshVolume>(elem);
+ domvol[idom] = (SMDS_MeshVolume*) svol;
+ //MESSAGE(" domain " << idom << " volume " << elem->GetID());
+ double values[3] = { 0,0,0 };
+ vtkIdType npts = 0;
+ vtkIdType const *pts(nullptr);
+ grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
+ for ( vtkIdType i = 0; i < npts; ++i )
+ {
+ double *coords = grid->GetPoint( pts[i] );
+ for ( int j = 0; j < 3; ++j )
+ values[j] += coords[j] / npts;
+ }
+ if ( id == 0 )
+ {
+ gref.SetCoord( values[0], values[1], values[2] );
+ angleDom[idom] = 0;
+ }
+ else
+ {
+ gp_Pnt g( values[0], values[1], values[2] );
+ angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
+ //MESSAGE(" angle=" << angleDom[idom]);
+ }
+ break;
}
+ }
+ }
+ map<double, int> sortedDom; // sort domains by angle
+ for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
+ sortedDom[ia->second] = ia->first;
+ vector<int> vnodes;
+ vector<int> vdom;
+ for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
+ {
+ vdom.push_back(ib->second);
+ //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
}
+ for (int ino = 0; ino < nbNodes; ino++)
+ vnodes.push_back(nodes[ino]);
+ edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
+ }
}
+ }
}
+ }
}
+ }
// --- iterate on shared faces (volumes to modify, face to extrude)
// get node id's of the face (id SMDS = id VTK)
std::map<int, std::map<long,int> > nodeQuadDomains;
std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
- MESSAGE(".. Creation of elements: simple junction");
+ //MESSAGE(".. Creation of elements: simple junction");
if (createJointElems)
- {
- int idg;
- string joints2DName = "joints2D";
- mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
- SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
- string joints3DName = "joints3D";
- mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
- SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
-
- 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> domvol = itface->second;
- std::map<int, int>::iterator itdom = domvol.begin();
- int dom1 = itdom->first;
- int vtkVolId = itdom->second;
- itdom++;
- int dom2 = itdom->first;
- SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
- nodeQuadDomains);
- stringstream grpname;
- grpname << "j_";
- if (dom1 < dom2)
- grpname << dom1 << "_" << dom2;
- else
- grpname << dom2 << "_" << dom1;
- string namegrp = grpname.str();
- if (!mapOfJunctionGroups.count(namegrp))
- mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
- SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
- if (sgrp)
- sgrp->Add(vol->GetID());
- if (vol->GetType() == SMDSAbs_Volume)
- joints3DGrp->Add(vol->GetID());
- else if (vol->GetType() == SMDSAbs_Face)
- joints2DGrp->Add(vol->GetID());
- }
+ {
+ string joints2DName = "joints2D";
+ mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str());
+ SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
+ string joints3DName = "joints3D";
+ mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str());
+ SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
+
+ 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> domvol = itface->second;
+ std::map<int, int>::iterator itdom = domvol.begin();
+ int dom1 = itdom->first;
+ int vtkVolId = itdom->second;
+ itdom++;
+ int dom2 = itdom->first;
+ SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
+ nodeQuadDomains);
+ stringstream grpname;
+ grpname << "j_";
+ if (dom1 < dom2)
+ grpname << dom1 << "_" << dom2;
+ else
+ grpname << dom2 << "_" << dom1;
+ string namegrp = grpname.str();
+ if (!mapOfJunctionGroups.count(namegrp))
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str());
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+ if (sgrp)
+ sgrp->Add(vol->GetID());
+ if (vol->GetType() == SMDSAbs_Volume)
+ joints3DGrp->Add(vol->GetID());
+ else if (vol->GetType() == SMDSAbs_Face)
+ joints2DGrp->Add(vol->GetID());
}
+ }
// --- create volumes on multiple domain intersection if requested
// iterate on mutipleNodesToFace
// iterate on edgesMultiDomains
- MESSAGE(".. Creation of elements: multiple junction");
+ //MESSAGE(".. Creation of elements: multiple junction");
if (createJointElems)
- {
- // --- iterate on mutipleNodesToFace
-
- std::map<int, std::vector<int> >::iterator itn = mutipleNodesToFace.begin();
- for (; itn != mutipleNodesToFace.end(); ++itn)
- {
- int node = itn->first;
- vector<int> orderDom = itn->second;
- vector<vtkIdType> orderedNodes;
- for (int idom = 0; idom <orderDom.size(); idom++)
- orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
- SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
-
- stringstream grpname;
- grpname << "m2j_";
- grpname << 0 << "_" << 0;
- int idg;
- string namegrp = grpname.str();
- if (!mapOfJunctionGroups.count(namegrp))
- mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
- SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
- if (sgrp)
- sgrp->Add(face->GetID());
- }
-
- // --- iterate on edgesMultiDomains
-
- std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
- for (; ite != edgesMultiDomains.end(); ++ite)
- {
- vector<int> nodes = ite->first;
- vector<int> orderDom = ite->second;
- vector<vtkIdType> orderedNodes;
- if (nodes.size() == 2)
- {
- //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
- for (int ino=0; ino < nodes.size(); ino++)
- if (orderDom.size() == 3)
- for (int idom = 0; idom <orderDom.size(); idom++)
- orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
- else
- for (int idom = orderDom.size()-1; idom >=0; idom--)
- orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
- SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
-
- int idg;
- string namegrp = "jointsMultiples";
- if (!mapOfJunctionGroups.count(namegrp))
- mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
- SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
- if (sgrp)
- sgrp->Add(vol->GetID());
- }
+ {
+ // --- iterate on mutipleNodesToFace
+
+ std::map<int, std::vector<int> >::iterator itn = mutipleNodesToFace.begin();
+ for (; itn != mutipleNodesToFace.end(); ++itn)
+ {
+ int node = itn->first;
+ vector<int> orderDom = itn->second;
+ vector<vtkIdType> orderedNodes;
+ for ( size_t idom = 0; idom < orderDom.size(); idom++ )
+ orderedNodes.push_back( nodeDomains[ node ][ orderDom[ idom ]]);
+ SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
+
+ stringstream grpname;
+ grpname << "m2j_";
+ grpname << 0 << "_" << 0;
+ string namegrp = grpname.str();
+ if (!mapOfJunctionGroups.count(namegrp))
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str());
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+ if (sgrp)
+ sgrp->Add(face->GetID());
+ }
+
+ // --- iterate on edgesMultiDomains
+
+ std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
+ for (; ite != edgesMultiDomains.end(); ++ite)
+ {
+ vector<int> nodes = ite->first;
+ vector<int> orderDom = ite->second;
+ vector<vtkIdType> orderedNodes;
+ if (nodes.size() == 2)
+ {
+ //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
+ for ( size_t ino = 0; ino < nodes.size(); ino++ )
+ if ( orderDom.size() == 3 )
+ for ( size_t idom = 0; idom < orderDom.size(); idom++ )
+ orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]);
else
- {
- INFOS("Quadratic multiple joints not implemented");
- // TODO quadratic nodes
- }
- }
+ for (int idom = orderDom.size()-1; idom >=0; idom--)
+ orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]);
+ SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
+
+ string namegrp = "jointsMultiples";
+ if (!mapOfJunctionGroups.count(namegrp))
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str());
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+ if (sgrp)
+ sgrp->Add(vol->GetID());
+ }
+ else
+ {
+ //INFOS("Quadratic multiple joints not implemented");
+ // TODO quadratic nodes
+ }
}
+ }
// --- list the explicit faces and edges of the mesh that need to be modified,
// i.e. faces and edges built with one or more duplicated nodes.
faceOrEdgeDom.clear();
feDom.clear();
- MESSAGE(".. Modification of elements");
- for (int idomain = 0; idomain < theElems.size(); idomain++)
+ //MESSAGE(".. Modification of elements");
+ for (int idomain = idom0; idomain < nbDomains; idomain++)
+ {
+ std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
+ for (; itnod != nodeDomains.end(); ++itnod)
{
- std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
- for (; itnod != nodeDomains.end(); ++itnod)
- {
- int oldId = itnod->first;
- //MESSAGE(" node " << oldId);
- vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
- for (int i = 0; i < l.ncells; i++)
+ int oldId = itnod->first;
+ //MESSAGE(" node " << oldId);
+ vtkCellLinks::Link l = (static_cast< vtkCellLinks *>(grid->GetCellLinks()))->GetLink(oldId);
+ for (int i = 0; i < l.ncells; i++)
+ {
+ int vtkId = l.cells[i];
+ int vtkType = grid->GetCellType(vtkId);
+ int downId = grid->CellIdToDownId(vtkId);
+ if (downId < 0)
+ continue; // new cells: not to be modified
+ DownIdType aCell(downId, vtkType);
+ int volParents[1000];
+ int nbvol = grid->GetParentVolumes(volParents, vtkId);
+ for (int j = 0; j < nbvol; j++)
+ if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
+ if (!feDom.count(vtkId))
{
- int vtkId = l.cells[i];
- int vtkType = grid->GetCellType(vtkId);
- int downId = grid->CellIdToDownId(vtkId);
- if (downId < 0)
- continue; // new cells: not to be modified
- DownIdType aCell(downId, vtkType);
- int volParents[1000];
- int nbvol = grid->GetParentVolumes(volParents, vtkId);
- for (int j = 0; j < nbvol; j++)
- if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
- if (!feDom.count(vtkId))
- {
- feDom[vtkId] = idomain;
- faceOrEdgeDom[aCell] = emptyMap;
- faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
- //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
- // << " type " << vtkType << " downId " << downId);
- }
+ feDom[vtkId] = idomain;
+ faceOrEdgeDom[aCell] = emptyMap;
+ faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
+ //MESSAGE("affect cell " << this->GetMeshDS()->FromVtkToSmds(vtkId) << " domain " << idomain
+ // << " type " << vtkType << " downId " << downId);
}
- }
+ }
}
+ }
// --- iterate on shared faces (volumes to modify, face to extrude)
// get node id's of the face
std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
for (int m=0; m<3; m++)
- {
- std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
- itface = (*amap).begin();
- for (; itface != (*amap).end(); ++itface)
+ {
+ std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
+ itface = (*amap).begin();
+ for (; itface != (*amap).end(); ++itface)
+ {
+ DownIdType face = itface->first;
+ std::set<int> oldNodes;
+ std::set<int>::iterator itn;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ //MESSAGE("examine cell, downId " << face.cellId << " type " << int(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)
+ {
+ int idom = itdom->first;
+ int vtkVolId = itdom->second;
+ //MESSAGE("modify nodes of cell " << this->GetMeshDS()->FromVtkToSmds(vtkVolId) << " domain " << idom);
+ localClonedNodeIds.clear();
+ for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
{
- DownIdType face = itface->first;
- std::set<int> oldNodes;
- std::set<int>::iterator itn;
- oldNodes.clear();
- grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
- //MESSAGE("examine cell, downId " << face.cellId << " type " << int(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)
- {
- int idom = itdom->first;
- int vtkVolId = itdom->second;
- //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
- localClonedNodeIds.clear();
- for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
- {
- int oldId = *itn;
- if (nodeDomains[oldId].count(idom))
- {
- localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
- //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
- }
- }
- meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
- }
+ int oldId = *itn;
+ if (nodeDomains[oldId].count(idom))
+ {
+ localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
+ //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
+ }
}
+ meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
+ }
}
+ }
+
+ // Remove empty groups (issue 0022812)
+ std::map<std::string, SMESH_Group*>::iterator name_group = mapOfJunctionGroups.begin();
+ for ( ; name_group != mapOfJunctionGroups.end(); ++name_group )
+ {
+ if ( name_group->second && name_group->second->GetGroupDS()->IsEmpty() )
+ myMesh->RemoveGroup( name_group->second->GetGroupDS()->GetID() );
+ }
meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
- grid->BuildLinks();
+ grid->DeleteLinks();
CHRONOSTOP(50);
counters::stats();
*/
bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
{
- MESSAGE("-------------------------------------------------");
- MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
- MESSAGE("-------------------------------------------------");
+ // MESSAGE("-------------------------------------------------");
+ // MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
+ // MESSAGE("-------------------------------------------------");
SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
mapOfJunctionGroups.clear();
- for (int idom = 0; idom < theElems.size(); idom++)
+ for ( size_t idom = 0; idom < theElems.size(); idom++ )
+ {
+ const TIDSortedElemSet& domain = theElems[idom];
+ TIDSortedElemSet::const_iterator elemItr = domain.begin();
+ for ( ; elemItr != domain.end(); ++elemItr )
{
- const TIDSortedElemSet& domain = theElems[idom];
- TIDSortedElemSet::const_iterator elemItr = domain.begin();
- for (; elemItr != domain.end(); ++elemItr)
- {
- SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
- SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
- if (!aFace)
- continue;
- // MESSAGE("aFace=" << aFace->GetID());
- bool isQuad = aFace->IsQuadratic();
- vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
-
- // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
-
- SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
- while (nodeIt->more())
- {
- const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
- bool isMedium = isQuad && (aFace->IsMediumNode(node));
- if (isMedium)
- ln2.push_back(node);
- else
- ln0.push_back(node);
+ const SMDS_MeshFace* aFace = meshDS->DownCast<SMDS_MeshFace> ( *elemItr );
+ if (!aFace)
+ continue;
+ // MESSAGE("aFace=" << aFace->GetID());
+ bool isQuad = aFace->IsQuadratic();
+ vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
- const SMDS_MeshNode* clone = 0;
- if (!clonedNodes.count(node))
- {
- clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
- clonedNodes[node] = clone;
- }
- else
- clone = clonedNodes[node];
+ // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
- if (isMedium)
- ln3.push_back(clone);
- else
- ln1.push_back(clone);
+ SMDS_NodeIteratorPtr nodeIt = aFace->nodeIterator();
+ while (nodeIt->more())
+ {
+ const SMDS_MeshNode* node = nodeIt->next();
+ bool isMedium = ( isQuad && aFace->IsMediumNode( node ));
+ if (isMedium)
+ ln2.push_back(node);
+ else
+ ln0.push_back(node);
- const SMDS_MeshNode* inter = 0;
- if (isQuad && (!isMedium))
- {
- if (!intermediateNodes.count(node))
- {
- inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
- intermediateNodes[node] = inter;
- }
- else
- inter = intermediateNodes[node];
- ln4.push_back(inter);
- }
- }
+ const SMDS_MeshNode* clone = 0;
+ if (!clonedNodes.count(node))
+ {
+ clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
+ copyPosition( node, clone );
+ clonedNodes[node] = clone;
+ }
+ else
+ clone = clonedNodes[node];
- // --- extrude the face
+ if (isMedium)
+ ln3.push_back(clone);
+ else
+ ln1.push_back(clone);
- vector<const SMDS_MeshNode*> ln;
- SMDS_MeshVolume* vol = 0;
- vtkIdType aType = aFace->GetVtkType();
- switch (aType)
+ const SMDS_MeshNode* inter = 0;
+ if (isQuad && (!isMedium))
+ {
+ if (!intermediateNodes.count(node))
{
- case VTK_TRIANGLE:
- vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
- // MESSAGE("vol prism " << vol->GetID());
- ln.push_back(ln1[0]);
- ln.push_back(ln1[1]);
- ln.push_back(ln1[2]);
- break;
- case VTK_QUAD:
- vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
- // MESSAGE("vol hexa " << vol->GetID());
- ln.push_back(ln1[0]);
- ln.push_back(ln1[1]);
- ln.push_back(ln1[2]);
- ln.push_back(ln1[3]);
- break;
- case VTK_QUADRATIC_TRIANGLE:
- vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
- ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
- // MESSAGE("vol quad prism " << vol->GetID());
- ln.push_back(ln1[0]);
- ln.push_back(ln1[1]);
- ln.push_back(ln1[2]);
- ln.push_back(ln3[0]);
- ln.push_back(ln3[1]);
- ln.push_back(ln3[2]);
- break;
- case VTK_QUADRATIC_QUAD:
-// vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
-// ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
-// ln4[0], ln4[1], ln4[2], ln4[3]);
- vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
- ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
- ln4[0], ln4[1], ln4[2], ln4[3]);
- // MESSAGE("vol quad hexa " << vol->GetID());
- ln.push_back(ln1[0]);
- ln.push_back(ln1[1]);
- ln.push_back(ln1[2]);
- ln.push_back(ln1[3]);
- ln.push_back(ln3[0]);
- ln.push_back(ln3[1]);
- ln.push_back(ln3[2]);
- ln.push_back(ln3[3]);
- break;
- case VTK_POLYGON:
- break;
- default:
- break;
+ inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
+ copyPosition( node, inter );
+ intermediateNodes[node] = inter;
}
+ else
+ inter = intermediateNodes[node];
+ ln4.push_back(inter);
+ }
+ }
- if (vol)
- {
- stringstream grpname;
- grpname << "jf_";
- grpname << idom;
- int idg;
- string namegrp = grpname.str();
- if (!mapOfJunctionGroups.count(namegrp))
- mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
- SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
- if (sgrp)
- sgrp->Add(vol->GetID());
- }
+ // --- extrude the face
+
+ vector<const SMDS_MeshNode*> ln;
+ SMDS_MeshVolume* vol = 0;
+ vtkIdType aType = aFace->GetVtkType();
+ switch (aType)
+ {
+ case VTK_TRIANGLE:
+ vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
+ // MESSAGE("vol prism " << vol->GetID());
+ ln.push_back(ln1[0]);
+ ln.push_back(ln1[1]);
+ ln.push_back(ln1[2]);
+ break;
+ case VTK_QUAD:
+ vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
+ // MESSAGE("vol hexa " << vol->GetID());
+ ln.push_back(ln1[0]);
+ ln.push_back(ln1[1]);
+ ln.push_back(ln1[2]);
+ ln.push_back(ln1[3]);
+ break;
+ case VTK_QUADRATIC_TRIANGLE:
+ vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
+ ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
+ // MESSAGE("vol quad prism " << vol->GetID());
+ ln.push_back(ln1[0]);
+ ln.push_back(ln1[1]);
+ ln.push_back(ln1[2]);
+ ln.push_back(ln3[0]);
+ ln.push_back(ln3[1]);
+ ln.push_back(ln3[2]);
+ break;
+ case VTK_QUADRATIC_QUAD:
+ // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
+ // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
+ // ln4[0], ln4[1], ln4[2], ln4[3]);
+ vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
+ ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
+ ln4[0], ln4[1], ln4[2], ln4[3]);
+ // MESSAGE("vol quad hexa " << vol->GetID());
+ ln.push_back(ln1[0]);
+ ln.push_back(ln1[1]);
+ ln.push_back(ln1[2]);
+ ln.push_back(ln1[3]);
+ ln.push_back(ln3[0]);
+ ln.push_back(ln3[1]);
+ ln.push_back(ln3[2]);
+ ln.push_back(ln3[3]);
+ break;
+ case VTK_POLYGON:
+ break;
+ default:
+ break;
+ }
+
+ if (vol)
+ {
+ stringstream grpname;
+ grpname << "jf_";
+ grpname << idom;
+ string namegrp = grpname.str();
+ if (!mapOfJunctionGroups.count(namegrp))
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str());
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+ if (sgrp)
+ sgrp->Add(vol->GetID());
+ }
- // --- modify the face
+ // --- modify the face
- aFace->ChangeNodes(&ln[0], ln.size());
- }
+ const_cast<SMDS_MeshFace*>( aFace )->ChangeNodes( &ln[0], ln.size() );
}
+ }
return true;
}
* groups of faces to remove inside the object, (idem edges).
* Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
*/
-void SMESH_MeshEditor::CreateHoleSkin(double radius,
- const TopoDS_Shape& theShape,
- SMESH_NodeSearcher* theNodeSearcher,
- const char* groupName,
- std::vector<double>& nodesCoords,
+void SMESH_MeshEditor::CreateHoleSkin(double radius,
+ const TopoDS_Shape& theShape,
+ SMESH_NodeSearcher* theNodeSearcher,
+ const char* groupName,
+ std::vector<double>& nodesCoords,
std::vector<std::vector<int> >& listOfListOfNodes)
{
- MESSAGE("--------------------------------");
- MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
- MESSAGE("--------------------------------");
+ // MESSAGE("--------------------------------");
+ // MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
+ // MESSAGE("--------------------------------");
// --- zone of volumes to remove is given :
// 1 either by a geom shape (one or more vertices) and a radius,
SMESHDS_GroupBase* groupDS = 0;
SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
while ( groupIt->more() )
- {
+ {
+ groupDS = 0;
+ SMESH_Group * group = groupIt->next();
+ if ( !group ) continue;
+ groupDS = group->GetGroupDS();
+ if ( !groupDS || groupDS->IsEmpty() ) continue;
+ std::string grpName = group->GetName();
+ //MESSAGE("grpName=" << grpName);
+ if (grpName == groupName)
+ break;
+ else
groupDS = 0;
- SMESH_Group * group = groupIt->next();
- if ( !group ) continue;
- groupDS = group->GetGroupDS();
- if ( !groupDS || groupDS->IsEmpty() ) continue;
- std::string grpName = group->GetName();
- //MESSAGE("grpName=" << grpName);
- if (grpName == groupName)
- break;
- else
- groupDS = 0;
- }
+ }
bool isNodeGroup = false;
bool isNodeCoords = false;
if (groupDS)
- {
- if (groupDS->GetType() != SMDSAbs_Node)
- return;
- isNodeGroup = true; // a group of nodes exists and it is in this mesh
- }
+ {
+ if (groupDS->GetType() != SMDSAbs_Node)
+ return;
+ isNodeGroup = true; // a group of nodes exists and it is in this mesh
+ }
if (nodesCoords.size() > 0)
isNodeCoords = true; // a list o nodes given by their coordinates
// --- define groups to build
- int idg; // --- group of SMDS volumes
+ // --- group of SMDS volumes
string grpvName = groupName;
grpvName += "_vol";
- SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
+ SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str());
if (!grp)
- {
- MESSAGE("group not created " << grpvName);
- return;
- }
+ {
+ MESSAGE("group not created " << grpvName);
+ return;
+ }
SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
- int idgs; // --- group of SMDS faces on the skin
+ // --- group of SMDS faces on the skin
string grpsName = groupName;
grpsName += "_skin";
- SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
+ SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str());
if (!grps)
- {
- MESSAGE("group not created " << grpsName);
- return;
- }
+ {
+ MESSAGE("group not created " << grpsName);
+ return;
+ }
SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
- int idgi; // --- group of SMDS faces internal (several shapes)
+ // --- group of SMDS faces internal (several shapes)
string grpiName = groupName;
grpiName += "_internalFaces";
- SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
+ SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str());
if (!grpi)
- {
- MESSAGE("group not created " << grpiName);
- return;
- }
+ {
+ MESSAGE("group not created " << grpiName);
+ return;
+ }
SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
- int idgei; // --- group of SMDS faces internal (several shapes)
+ // --- group of SMDS faces internal (several shapes)
string grpeiName = groupName;
grpeiName += "_internalEdges";
- SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
+ SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str());
if (!grpei)
- {
- MESSAGE("group not created " << grpeiName);
- return;
- }
+ {
+ MESSAGE("group not created " << grpeiName);
+ return;
+ }
SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
// --- build downward connectivity
SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
meshDS->BuildDownWardConnectivity(true);
- SMDS_UnstructuredGrid* grid = meshDS->getGrid();
+ SMDS_UnstructuredGrid* grid = meshDS->GetGrid();
// --- set of volumes detected inside
gpnts.clear();
if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
+ {
+ //MESSAGE("group of nodes provided");
+ SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
+ while ( elemIt->more() )
{
- MESSAGE("group of nodes provided");
- SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
- while ( elemIt->more() )
- {
- const SMDS_MeshElement* elem = elemIt->next();
- if (!elem)
- continue;
- const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
- if (!node)
- continue;
- SMDS_MeshElement* vol = 0;
- SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
- while (volItr->more())
- {
- vol = (SMDS_MeshElement*)volItr->next();
- setOfInsideVol.insert(vol->getVtkId());
- sgrp->Add(vol->GetID());
- }
- }
+ const SMDS_MeshElement* elem = elemIt->next();
+ if (!elem)
+ continue;
+ const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
+ if (!node)
+ continue;
+ SMDS_MeshElement* vol = 0;
+ SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
+ while (volItr->more())
+ {
+ vol = (SMDS_MeshElement*)volItr->next();
+ setOfInsideVol.insert(vol->GetVtkID());
+ sgrp->Add(vol->GetID());
+ }
}
+ }
else if (isNodeCoords)
+ {
+ //MESSAGE("list of nodes coordinates provided");
+ size_t i = 0;
+ int k = 0;
+ while ( i < nodesCoords.size()-2 )
{
- MESSAGE("list of nodes coordinates provided");
- int i = 0;
- int k = 0;
- while (i < nodesCoords.size()-2)
- {
- double x = nodesCoords[i++];
- double y = nodesCoords[i++];
- double z = nodesCoords[i++];
- gp_Pnt p = gp_Pnt(x, y ,z);
- gpnts.push_back(p);
- MESSAGE("TopoDS_Vertex " << k++ << " " << p.X() << " " << p.Y() << " " << p.Z());
- }
+ double x = nodesCoords[i++];
+ double y = nodesCoords[i++];
+ double z = nodesCoords[i++];
+ gp_Pnt p = gp_Pnt(x, y ,z);
+ gpnts.push_back(p);
+ //MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
+ k++;
}
+ }
else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
- {
- MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
- TopTools_IndexedMapOfShape vertexMap;
- TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
- gp_Pnt p = gp_Pnt(0,0,0);
- if (vertexMap.Extent() < 1)
- return;
+ {
+ //MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
+ TopTools_IndexedMapOfShape vertexMap;
+ TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
+ gp_Pnt p = gp_Pnt(0,0,0);
+ if (vertexMap.Extent() < 1)
+ return;
- for ( int i = 1; i <= vertexMap.Extent(); ++i )
- {
- const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
- p = BRep_Tool::Pnt(vertex);
- gpnts.push_back(p);
- MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
- }
+ for ( int i = 1; i <= vertexMap.Extent(); ++i )
+ {
+ const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
+ p = BRep_Tool::Pnt(vertex);
+ gpnts.push_back(p);
+ //MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
}
+ }
if (gpnts.size() > 0)
- {
- int nodeId = 0;
- const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
- if (startNode)
- nodeId = startNode->GetID();
- MESSAGE("nodeId " << nodeId);
+ {
+ const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
+ //MESSAGE("startNode->nodeId " << nodeId);
- double radius2 = radius*radius;
- MESSAGE("radius2 " << radius2);
+ double radius2 = radius*radius;
+ //MESSAGE("radius2 " << radius2);
- // --- volumes on start node
+ // --- volumes on start node
- setOfVolToCheck.clear();
- SMDS_MeshElement* startVol = 0;
- SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
- while (volItr->more())
- {
- startVol = (SMDS_MeshElement*)volItr->next();
- setOfVolToCheck.insert(startVol->getVtkId());
- }
- if (setOfVolToCheck.empty())
- {
- MESSAGE("No volumes found");
- return;
- }
+ setOfVolToCheck.clear();
+ SMDS_MeshElement* startVol = 0;
+ SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
+ while (volItr->more())
+ {
+ startVol = (SMDS_MeshElement*)volItr->next();
+ setOfVolToCheck.insert(startVol->GetVtkID());
+ }
+ if (setOfVolToCheck.empty())
+ {
+ MESSAGE("No volumes found");
+ return;
+ }
- // --- starting with central volumes then their neighbors, check if they are inside
- // or outside the domain, until no more new neighbor volume is inside.
- // Fill the group of inside volumes
+ // --- starting with central volumes then their neighbors, check if they are inside
+ // or outside the domain, until no more new neighbor volume is inside.
+ // Fill the group of inside volumes
- std::map<int, double> mapOfNodeDistance2;
- mapOfNodeDistance2.clear();
- std::set<int> setOfOutsideVol;
- while (!setOfVolToCheck.empty())
+ std::map<int, double> mapOfNodeDistance2;
+ mapOfNodeDistance2.clear();
+ std::set<int> setOfOutsideVol;
+ while (!setOfVolToCheck.empty())
+ {
+ std::set<int>::iterator it = setOfVolToCheck.begin();
+ int vtkId = *it;
+ //MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
+ bool volInside = false;
+ vtkIdType npts = 0;
+ vtkIdType const *pts(nullptr);
+ grid->GetCellPoints(vtkId, npts, pts);
+ for (int i=0; i<npts; i++)
+ {
+ double distance2 = 0;
+ if (mapOfNodeDistance2.count(pts[i]))
+ {
+ distance2 = mapOfNodeDistance2[pts[i]];
+ //MESSAGE("point " << pts[i] << " distance2 " << distance2);
+ }
+ else
{
- std::set<int>::iterator it = setOfVolToCheck.begin();
- int vtkId = *it;
- MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
- bool volInside = false;
- vtkIdType npts = 0;
- vtkIdType* pts = 0;
- grid->GetCellPoints(vtkId, npts, pts);
- for (int i=0; i<npts; i++)
+ double *coords = grid->GetPoint(pts[i]);
+ gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
+ distance2 = 1.E40;
+ for ( size_t j = 0; j < gpnts.size(); j++ )
+ {
+ double d2 = aPoint.SquareDistance( gpnts[ j ]);
+ if (d2 < distance2)
{
- double distance2 = 0;
- if (mapOfNodeDistance2.count(pts[i]))
- {
- distance2 = mapOfNodeDistance2[pts[i]];
- MESSAGE("point " << pts[i] << " distance2 " << distance2);
- }
- else
- {
- double *coords = grid->GetPoint(pts[i]);
- gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
- distance2 = 1.E40;
- for (int j=0; j<gpnts.size(); j++)
- {
- double d2 = aPoint.SquareDistance(gpnts[j]);
- if (d2 < distance2)
- {
- distance2 = d2;
- if (distance2 < radius2)
- break;
- }
- }
- mapOfNodeDistance2[pts[i]] = distance2;
- MESSAGE(" point " << pts[i] << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " << coords[2]);
- }
+ distance2 = d2;
if (distance2 < radius2)
- {
- volInside = true; // one or more nodes inside the domain
- sgrp->Add(meshDS->fromVtkToSmds(vtkId));
- break;
- }
- }
- if (volInside)
- {
- setOfInsideVol.insert(vtkId);
- MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
- 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++)
- if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
- setOfVolToCheck.insert(neighborsVtkIds[n]);
- }
- else
- {
- setOfOutsideVol.insert(vtkId);
- MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+ break;
}
- setOfVolToCheck.erase(vtkId);
+ }
+ mapOfNodeDistance2[pts[i]] = distance2;
+ //MESSAGE(" point " << pts[i] << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " << coords[2]);
+ }
+ if (distance2 < radius2)
+ {
+ volInside = true; // one or more nodes inside the domain
+ sgrp->Add(meshDS->FromVtkToSmds(vtkId));
+ break;
}
+ }
+ if (volInside)
+ {
+ setOfInsideVol.insert(vtkId);
+ //MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
+ 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++)
+ if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
+ setOfVolToCheck.insert(neighborsVtkIds[n]);
+ }
+ else
+ {
+ setOfOutsideVol.insert(vtkId);
+ //MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
+ }
+ setOfVolToCheck.erase(vtkId);
}
+ }
// --- for outside hexahedrons, check if they have more than one neighbor volume inside
// If yes, add the volume to the inside set
bool addedInside = true;
std::set<int> setOfVolToReCheck;
while (addedInside)
+ {
+ //MESSAGE(" --------------------------- re check");
+ addedInside = false;
+ std::set<int>::iterator itv = setOfInsideVol.begin();
+ for (; itv != setOfInsideVol.end(); ++itv)
{
- MESSAGE(" --------------------------- re check");
- addedInside = false;
- std::set<int>::iterator itv = setOfInsideVol.begin();
- for (; itv != setOfInsideVol.end(); ++itv)
- {
- int vtkId = *itv;
- 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++)
- if (!setOfInsideVol.count(neighborsVtkIds[n]))
- setOfVolToReCheck.insert(neighborsVtkIds[n]);
- }
- setOfVolToCheck = setOfVolToReCheck;
- setOfVolToReCheck.clear();
- while (!setOfVolToCheck.empty())
+ int vtkId = *itv;
+ 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++)
+ if (!setOfInsideVol.count(neighborsVtkIds[n]))
+ setOfVolToReCheck.insert(neighborsVtkIds[n]);
+ }
+ setOfVolToCheck = setOfVolToReCheck;
+ setOfVolToReCheck.clear();
+ while (!setOfVolToCheck.empty())
+ {
+ std::set<int>::iterator it = setOfVolToCheck.begin();
+ int vtkId = *it;
+ if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
+ {
+ //MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
+ int countInside = 0;
+ 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++)
+ if (setOfInsideVol.count(neighborsVtkIds[n]))
+ countInside++;
+ //MESSAGE("countInside " << countInside);
+ if (countInside > 1)
{
- std::set<int>::iterator it = setOfVolToCheck.begin();
- int vtkId = *it;
- if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
- {
- MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
- int countInside = 0;
- 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++)
- if (setOfInsideVol.count(neighborsVtkIds[n]))
- countInside++;
- MESSAGE("countInside " << countInside);
- if (countInside > 1)
- {
- MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
- setOfInsideVol.insert(vtkId);
- sgrp->Add(meshDS->fromVtkToSmds(vtkId));
- addedInside = true;
- }
- else
- setOfVolToReCheck.insert(vtkId);
- }
- setOfVolToCheck.erase(vtkId);
+ //MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
+ setOfInsideVol.insert(vtkId);
+ sgrp->Add(meshDS->FromVtkToSmds(vtkId));
+ addedInside = true;
}
+ else
+ setOfVolToReCheck.insert(vtkId);
+ }
+ setOfVolToCheck.erase(vtkId);
}
+ }
// --- map of Downward faces at the boundary, inside the global volume
// map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
std::map<DownIdType, int, DownIdCompare> skinFaces; // faces on the skin of the global volume --> corresponding cell
std::set<int>::iterator it = setOfInsideVol.begin();
for (; it != setOfInsideVol.end(); ++it)
- {
- int vtkId = *it;
- //MESSAGE(" vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
- int neighborsVtkIds[NBMAXNEIGHBORS];
- int downIds[NBMAXNEIGHBORS];
- unsigned char downTypes[NBMAXNEIGHBORS];
- int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
- for (int n = 0; n < nbNeighbors; n++)
+ {
+ int vtkId = *it;
+ //MESSAGE(" vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
+ int neighborsVtkIds[NBMAXNEIGHBORS];
+ int downIds[NBMAXNEIGHBORS];
+ unsigned char downTypes[NBMAXNEIGHBORS];
+ int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
+ for (int n = 0; n < nbNeighbors; n++)
+ {
+ int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
+ if (neighborDim == 3)
+ {
+ if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
{
- int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
- if (neighborDim == 3)
- {
- if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
- {
- DownIdType face(downIds[n], downTypes[n]);
- boundaryFaces[face] = vtkId;
- }
- // if the face between to volumes is in the mesh, get it (internal face between shapes)
- int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
- if (vtkFaceId >= 0)
- {
- sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
- // find also the smds edges on this face
- int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
- const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
- const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
- for (int i = 0; i < nbEdges; i++)
- {
- int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
- if (vtkEdgeId >= 0)
- sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
- }
- }
- }
- else if (neighborDim == 2) // skin of the volume
- {
- DownIdType face(downIds[n], downTypes[n]);
- skinFaces[face] = vtkId;
- int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
- if (vtkFaceId >= 0)
- sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
- }
+ DownIdType face(downIds[n], downTypes[n]);
+ boundaryFaces[face] = vtkId;
+ }
+ // if the face between to volumes is in the mesh, get it (internal face between shapes)
+ int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
+ if (vtkFaceId >= 0)
+ {
+ sgrpi->Add(meshDS->FromVtkToSmds(vtkFaceId));
+ // find also the smds edges on this face
+ int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
+ const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
+ const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
+ for (int i = 0; i < nbEdges; i++)
+ {
+ int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
+ if (vtkEdgeId >= 0)
+ sgrpei->Add(meshDS->FromVtkToSmds(vtkEdgeId));
+ }
}
+ }
+ else if (neighborDim == 2) // skin of the volume
+ {
+ DownIdType face(downIds[n], downTypes[n]);
+ skinFaces[face] = vtkId;
+ int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
+ if (vtkFaceId >= 0)
+ sgrps->Add(meshDS->FromVtkToSmds(vtkFaceId));
+ }
}
+ }
// --- identify the edges constituting the wire of each subshape on the skin
// define polylines with the nodes of edges, equivalent to wires
SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
while (itelem->more())
+ {
+ const SMDS_MeshElement *elem = itelem->next();
+ int shapeId = elem->getshapeId();
+ int vtkId = elem->GetVtkID();
+ if (!shapeIdToVtkIdSet.count(shapeId))
{
- const SMDS_MeshElement *elem = itelem->next();
- int shapeId = elem->getshapeId();
- int vtkId = elem->getVtkId();
- if (!shapeIdToVtkIdSet.count(shapeId))
- {
- shapeIdToVtkIdSet[shapeId] = emptySet;
- shapeIds.insert(shapeId);
- }
- shapeIdToVtkIdSet[shapeId].insert(vtkId);
+ shapeIdToVtkIdSet[shapeId] = emptySet;
+ shapeIds.insert(shapeId);
}
+ shapeIdToVtkIdSet[shapeId].insert(vtkId);
+ }
std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
std::set<DownIdType, DownIdCompare> emptyEdges;
std::map<int, std::set<int> >::iterator itShape = shapeIdToVtkIdSet.begin();
for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
- {
- int shapeId = itShape->first;
- MESSAGE(" --- Shape ID --- "<< shapeId);
- shapeIdToEdges[shapeId] = emptyEdges;
+ {
+ int shapeId = itShape->first;
+ //MESSAGE(" --- Shape ID --- "<< shapeId);
+ shapeIdToEdges[shapeId] = emptyEdges;
- std::vector<int> nodesEdges;
+ std::vector<int> nodesEdges;
- std::set<int>::iterator its = itShape->second.begin();
- for (; its != itShape->second.end(); ++its)
+ std::set<int>::iterator its = itShape->second.begin();
+ for (; its != itShape->second.end(); ++its)
+ {
+ int vtkId = *its;
+ //MESSAGE(" " << vtkId);
+ 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++)
+ {
+ if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
+ continue;
+ smIdType smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
+ const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
+ if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
{
- int vtkId = *its;
- MESSAGE(" " << vtkId);
- 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++)
- {
- if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
- continue;
- int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
- const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
- if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
- {
- DownIdType edge(downIds[n], downTypes[n]);
- if (!shapeIdToEdges[shapeId].count(edge))
- {
- shapeIdToEdges[shapeId].insert(edge);
- int vtkNodeId[3];
- int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
- nodesEdges.push_back(vtkNodeId[0]);
- nodesEdges.push_back(vtkNodeId[nbNodes-1]);
- MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
- }
- }
- }
+ DownIdType edge(downIds[n], downTypes[n]);
+ if (!shapeIdToEdges[shapeId].count(edge))
+ {
+ shapeIdToEdges[shapeId].insert(edge);
+ int vtkNodeId[3];
+ int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
+ nodesEdges.push_back(vtkNodeId[0]);
+ nodesEdges.push_back(vtkNodeId[nbNodes-1]);
+ //MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
+ }
}
+ }
+ }
- std::list<int> order;
- order.clear();
- if (nodesEdges.size() > 0)
+ std::list<int> order;
+ order.clear();
+ if (nodesEdges.size() > 0)
+ {
+ order.push_back(nodesEdges[0]); //MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1;
+ nodesEdges[0] = -1;
+ order.push_back(nodesEdges[1]); //MESSAGE(" --- back " << order.back()+1);
+ nodesEdges[1] = -1; // do not reuse this edge
+ bool found = true;
+ while (found)
+ {
+ int nodeTofind = order.back(); // try first to push back
+ int i = 0;
+ for ( i = 0; i < (int)nodesEdges.size(); i++ )
+ if (nodesEdges[i] == nodeTofind)
+ break;
+ if ( i == (int) nodesEdges.size() )
+ found = false; // no follower found on back
+ else
{
- order.push_back(nodesEdges[0]); MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1;
- nodesEdges[0] = -1;
- order.push_back(nodesEdges[1]); MESSAGE(" --- back " << order.back()+1);
- nodesEdges[1] = -1; // do not reuse this edge
- bool found = true;
- while (found)
+ if (i%2) // odd ==> use the previous one
+ if (nodesEdges[i-1] < 0)
+ found = false;
+ else
{
- int nodeTofind = order.back(); // try first to push back
- int i = 0;
- for (i = 0; i<nodesEdges.size(); i++)
- if (nodesEdges[i] == nodeTofind)
- break;
- if (i == nodesEdges.size())
- found = false; // no follower found on back
- else
- {
- if (i%2) // odd ==> use the previous one
- if (nodesEdges[i-1] < 0)
- found = false;
- else
- {
- order.push_back(nodesEdges[i-1]); MESSAGE(" --- back " << order.back()+1);
- nodesEdges[i-1] = -1;
- }
- else // even ==> use the next one
- if (nodesEdges[i+1] < 0)
- found = false;
- else
- {
- order.push_back(nodesEdges[i+1]); MESSAGE(" --- back " << order.back()+1);
- nodesEdges[i+1] = -1;
- }
- }
- if (found)
- continue;
- // try to push front
- found = true;
- nodeTofind = order.front(); // try to push front
- for (i = 0; i<nodesEdges.size(); i++)
- if (nodesEdges[i] == nodeTofind)
- break;
- if (i == nodesEdges.size())
- {
- found = false; // no predecessor found on front
- continue;
- }
- if (i%2) // odd ==> use the previous one
- if (nodesEdges[i-1] < 0)
- found = false;
- else
- {
- order.push_front(nodesEdges[i-1]); MESSAGE(" --- front " << order.front()+1);
- nodesEdges[i-1] = -1;
- }
- else // even ==> use the next one
- if (nodesEdges[i+1] < 0)
- found = false;
- else
- {
- order.push_front(nodesEdges[i+1]); MESSAGE(" --- front " << order.front()+1);
- nodesEdges[i+1] = -1;
- }
+ order.push_back(nodesEdges[i-1]); //MESSAGE(" --- back " << order.back()+1);
+ nodesEdges[i-1] = -1;
+ }
+ else // even ==> use the next one
+ if (nodesEdges[i+1] < 0)
+ found = false;
+ else
+ {
+ order.push_back(nodesEdges[i+1]); //MESSAGE(" --- back " << order.back()+1);
+ nodesEdges[i+1] = -1;
}
}
-
-
- std::vector<int> nodes;
- nodes.push_back(shapeId);
- std::list<int>::iterator itl = order.begin();
- for (; itl != order.end(); itl++)
+ if (found)
+ continue;
+ // try to push front
+ found = true;
+ nodeTofind = order.front(); // try to push front
+ for ( i = 0; i < (int)nodesEdges.size(); i++ )
+ if ( nodesEdges[i] == nodeTofind )
+ break;
+ if ( i == (int)nodesEdges.size() )
{
- nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
- MESSAGE(" ordered node " << nodes[nodes.size()-1]);
+ found = false; // no predecessor found on front
+ continue;
}
- listOfListOfNodes.push_back(nodes);
+ if (i%2) // odd ==> use the previous one
+ if (nodesEdges[i-1] < 0)
+ found = false;
+ else
+ {
+ order.push_front(nodesEdges[i-1]); //MESSAGE(" --- front " << order.front()+1);
+ nodesEdges[i-1] = -1;
+ }
+ else // even ==> use the next one
+ if (nodesEdges[i+1] < 0)
+ found = false;
+ else
+ {
+ order.push_front(nodesEdges[i+1]); //MESSAGE(" --- front " << order.front()+1);
+ nodesEdges[i+1] = -1;
+ }
+ }
+ }
+
+
+ std::vector<int> nodes;
+ nodes.push_back(shapeId);
+ std::list<int>::iterator itl = order.begin();
+ for (; itl != order.end(); itl++)
+ {
+ nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
+ //MESSAGE(" ordered node " << nodes[nodes.size()-1]);
}
+ listOfListOfNodes.push_back(nodes);
+ }
// partition geom faces with blocFissure
// mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
SMESHDS_Mesh* aMesh = GetMeshDS();
if (!aMesh)
return false;
- //bool res = false;
+
+ ElemFeatures faceType( SMDSAbs_Face );
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, /*ignoreCentralNodes=*/false );
vTool.SetExternalNormal();
- //const bool isPoly = volume->IsPoly();
const int iQuad = volume->IsQuadratic();
+ faceType.SetQuad( iQuad );
for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
{
if (!vTool.IsFreeFace(iface))
int inode = 0;
for ( ; inode < nbFaceNodes; inode += iQuad+1)
nodes.push_back(faceNodes[inode]);
- if (iQuad) { // add medium nodes
+
+ if (iQuad) // add medium nodes
+ {
for ( inode = 1; inode < nbFaceNodes; inode += 2)
nodes.push_back(faceNodes[inode]);
if ( nbFaceNodes == 9 ) // bi-quadratic quad
nodes.push_back(faceNodes[8]);
}
// add new face based on volume nodes
- if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
- nbExisted++;
- continue; // face already exsist
+ if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) )
+ {
+ nbExisted++; // face already exists
+ }
+ else
+ {
+ AddElement( nodes, faceType.SetPoly( nbFaceNodes/(iQuad+1) > 4 ));
+ nbCreated++;
}
- AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
- nbCreated++;
}
}
- return ( nbFree==(nbExisted+nbCreated) );
+ return ( nbFree == ( nbExisted + nbCreated ));
}
namespace
SMDS_VolumeTool vTool;
TIDSortedElemSet avoidSet;
const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
- int inode;
+ size_t inode;
typedef vector<const SMDS_MeshNode*> TConnectivity;
+ TConnectivity tgtNodes;
+ ElemFeatures elemKind( missType ), elemToCopy;
+
+ vector<const SMDS_MeshElement*> presentBndElems;
+ vector<TConnectivity> missingBndElems;
+ vector<int> freeFacets;
+ TConnectivity nodes, elemNodes;
SMDS_ElemIteratorPtr eIt;
- if (elements.empty())
- eIt = aMesh->elementsIterator(elemType);
- else
- eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+ if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
+ else eIt = SMESHUtils::elemSetIterator( elements );
- while (eIt->more())
+ while ( eIt->more() )
{
const SMDS_MeshElement* elem = eIt->next();
- const int iQuad = elem->IsQuadratic();
+ const int iQuad = elem->IsQuadratic();
+ elemKind.SetQuad( iQuad );
// ------------------------------------------------------------------------------------
// 1. For an elem, get present bnd elements and connectivities of missing bnd elements
// ------------------------------------------------------------------------------------
- vector<const SMDS_MeshElement*> presentBndElems;
- vector<TConnectivity> missingBndElems;
- TConnectivity nodes;
+ presentBndElems.clear();
+ missingBndElems.clear();
+ freeFacets.clear(); nodes.clear(); elemNodes.clear();
if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
{
- vTool.SetExternalNormal();
const SMDS_MeshElement* otherVol = 0;
for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
{
if ( !vTool.IsFreeFace(iface, &otherVol) &&
( !aroundElements || elements.count( otherVol )))
continue;
- const int nbFaceNodes = vTool.NbFaceNodes(iface);
+ freeFacets.push_back( iface );
+ }
+ if ( missType == SMDSAbs_Face )
+ vTool.SetExternalNormal();
+ for ( size_t i = 0; i < freeFacets.size(); ++i )
+ {
+ int iface = freeFacets[i];
const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
+ const size_t nbFaceNodes = vTool.NbFaceNodes (iface);
if ( missType == SMDSAbs_Edge ) // boundary edges
{
nodes.resize( 2+iQuad );
- for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
+ for ( size_t i = 0; i < nbFaceNodes; i += 1+iQuad )
{
- for ( int j = 0; j < nodes.size(); ++j )
- nodes[j] =nn[i+j];
+ for ( size_t j = 0; j < nodes.size(); ++j )
+ nodes[ j ] = nn[ i+j ];
if ( const SMDS_MeshElement* edge =
- aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
+ aMesh->FindElement( nodes, SMDSAbs_Edge, /*noMedium=*/false ))
presentBndElems.push_back( edge );
else
missingBndElems.push_back( nodes );
{
nodes.clear();
for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
- nodes.push_back( nn[inode] );
- if (iQuad) // add medium nodes
+ nodes.push_back( nn[inode] ); // add corner nodes
+ if (iQuad)
for ( inode = 1; inode < nbFaceNodes; inode += 2)
- nodes.push_back( nn[inode] );
+ nodes.push_back( nn[inode] ); // add medium nodes
int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
if ( iCenter > 0 )
nodes.push_back( vTool.GetNodes()[ iCenter ] );
}
}
}
- else // elem is a face ------------------------------------------
+ else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
{
avoidSet.clear(), avoidSet.insert( elem );
- int nbNodes = elem->NbCornerNodes();
- nodes.resize( 2 /*+ iQuad*/);
- for ( int i = 0; i < nbNodes; i++ )
+ elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesIterator() ),
+ SMDS_MeshElement::iterator() );
+ elemNodes.push_back( elemNodes[0] );
+ nodes.resize( 2 + iQuad );
+ const int nbLinks = elem->NbCornerNodes();
+ for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
{
- nodes[0] = elem->GetNode(i);
- nodes[1] = elem->GetNode((i+1)%nbNodes);
- if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
+ nodes[0] = elemNodes[iN];
+ nodes[1] = elemNodes[iN+1+iQuad];
+ if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
continue; // not free link
- //if ( iQuad )
- //nodes[2] = elem->GetNode( i + nbNodes );
+ if ( iQuad ) nodes[2] = elemNodes[iN+1];
if ( const SMDS_MeshElement* edge =
- aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
+ aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
presentBndElems.push_back( edge );
else
missingBndElems.push_back( nodes );
if ( targetMesh != myMesh )
// instead of making a map of nodes in this mesh and targetMesh,
// we create nodes with same IDs.
- for ( int i = 0; i < missingBndElems.size(); ++i )
+ for ( size_t 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] );
- if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
- missType,
- /*noMedium=*/false))
+ tgtNodes.resize( srcNodes.size() );
+ for ( inode = 0; inode < srcNodes.size(); ++inode )
+ tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
+ if ( /*aroundElements && */tgtEditor.GetMeshDS()->FindElement( tgtNodes,
+ missType,
+ /*noMedium=*/false))
continue;
- tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
+ tgtEditor.AddElement( tgtNodes, elemKind.SetPoly( tgtNodes.size()/(iQuad+1) > 4 ));
++nbAddedBnd;
}
else
- for ( int i = 0; i < missingBndElems.size(); ++i )
+ for ( size_t i = 0; i < missingBndElems.size(); ++i )
{
- TConnectivity& nodes = missingBndElems[i];
- if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
- missType,
- /*noMedium=*/false))
+ TConnectivity& nodes = missingBndElems[ i ];
+ if ( /*aroundElements && */tgtEditor.GetMeshDS()->FindElement( nodes,
+ missType,
+ /*noMedium=*/false))
continue;
- SMDS_MeshElement* elem =
- tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
- ++nbAddedBnd;
+ SMDS_MeshElement* newElem =
+ tgtEditor.AddElement( nodes, elemKind.SetPoly( nodes.size()/(iQuad+1) > 4 ));
+ nbAddedBnd += bool( newElem );
// try to set a new element to a shape
if ( myMesh->HasShapeToMesh() )
{
bool ok = true;
set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
- const int nbN = nodes.size() / (iQuad+1 );
+ const size_t nbN = nodes.size() / (iQuad+1 );
for ( inode = 0; inode < nbN && ok; ++inode )
{
pair<int, TopAbs_ShapeEnum> i_stype =
}
}
if ( ok && mediumShapes.begin()->first == missShapeType )
- aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
+ aMesh->SetMeshElementOnShape( newElem, mediumShapes.begin()->second );
}
}
// 3. Copy present boundary elements
// ----------------------------------
if ( toCopyExistingBoundary )
- for ( int i = 0 ; i < presentBndElems.size(); ++i )
+ for ( size_t 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) );
- presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
+ tgtNodes.resize( e->NbNodes() );
+ for ( inode = 0; inode < tgtNodes.size(); ++inode )
+ tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
+ presentEditor->AddElement( tgtNodes, elemToCopy.Init( e ));
}
else // store present elements to add them to a group
- for ( int i = 0 ; i < presentBndElems.size(); ++i )
+ for ( size_t i = 0 ; i < presentBndElems.size(); ++i )
{
- presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
+ presentEditor->myLastCreatedElems.push_back( presentBndElems[ i ]);
}
} // loop on given 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 ));
+ for ( size_t i = 0; i < tgtEditor.myLastCreatedElems.size(); ++i )
+ g->SMDSGroup().Add( tgtEditor.myLastCreatedElems[ i ]);
}
- tgtEditor.myLastCreatedElems.Clear();
- tgtEditor2.myLastCreatedElems.Clear();
+ tgtEditor.myLastCreatedElems.clear();
+ tgtEditor2.myLastCreatedElems.clear();
// -----------------------
// 5. Copy given elements
// -----------------------
if ( toCopyElements && targetMesh != myMesh )
{
- if (elements.empty())
- eIt = aMesh->elementsIterator(elemType);
- else
- eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+ if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
+ else eIt = SMESHUtils::elemSetIterator( elements );
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());
+ tgtNodes.resize( elem->NbNodes() );
+ for ( inode = 0; inode < tgtNodes.size(); ++inode )
+ tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
+ tgtEditor.AddElement( tgtNodes, elemToCopy.Init( elem ));
- tgtEditor.myLastCreatedElems.Clear();
+ tgtEditor.myLastCreatedElems.clear();
}
}
return nbAddedBnd;
}
+
+//================================================================================
+/*!
+ * \brief Copy node position and set \a to node on the same geometry
+ */
+//================================================================================
+
+void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from,
+ const SMDS_MeshNode* to )
+{
+ if ( !from || !to ) return;
+
+ SMDS_PositionPtr pos = from->GetPosition();
+ if ( !pos || from->getshapeId() < 1 ) return;
+
+ switch ( pos->GetTypeOfPosition() )
+ {
+ case SMDS_TOP_3DSPACE: break;
+
+ case SMDS_TOP_FACE:
+ {
+ SMDS_FacePositionPtr fPos = pos;
+ GetMeshDS()->SetNodeOnFace( to, from->getshapeId(),
+ fPos->GetUParameter(), fPos->GetVParameter() );
+ break;
+ }
+ case SMDS_TOP_EDGE:
+ {
+ // WARNING: it is dangerous to set equal nodes on one EDGE!!!!!!!!
+ SMDS_EdgePositionPtr ePos = pos;
+ GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() );
+ break;
+ }
+ case SMDS_TOP_VERTEX:
+ {
+ GetMeshDS()->SetNodeOnVertex( to, from->getshapeId() );
+ break;
+ }
+ case SMDS_TOP_UNSPEC:
+ default:;
+ }
+}