-// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2015 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_Algo.hxx"
#include "SMESH_ControlsDef.hxx"
#include "SMESH_Group.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 <algorithm>
#include <sstream>
+#include <boost/tuple/tuple.hpp>
+
#include <Standard_Failure.hxx>
#include <Standard_ErrorHandler.hxx>
using namespace std;
using namespace SMESH::Controls;
-typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
-typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
-
-typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
+namespace
+{
+ template < class ELEM_SET >
+ SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
+ {
+ typedef SMDS_SetIterator
+ < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
+ return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+ }
+}
//=======================================================================
//function : SMESH_MeshEditor
{
}
+//================================================================================
+/*!
+ * \brief Clears myLastCreatedNodes and myLastCreatedElems
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ClearLastCreated()
+{
+ myLastCreatedNodes.Clear();
+ myLastCreatedElems.Clear();
+}
+
+//================================================================================
+/*!
+ * \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 )
+ {
+ vector<int > quant = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
+ myPolyhedQuantities.swap( quant );
+ }
+ }
+ }
+ else if ( myType == SMDSAbs_Ball && !basicOnly )
+ {
+ myBallDiameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
+ }
+ }
+ return *this;
+}
+
//=======================================================================
/*!
* \brief Add element
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 int 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[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:;
*/
//=======================================================================
-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<int> & nodeIDs,
+ const ElemFeatures& features)
{
vector<const SMDS_MeshNode*> nodes;
nodes.reserve( nodeIDs.size() );
else
return 0;
}
- return AddElement( nodes, type, isPoly, ID );
+ return AddElement( nodes, features );
}
//=======================================================================
return removed;
}
+//================================================================================
+/*!
+ * \brief Create 0D elements on all nodes of the given object except those
+ * nodes on which a 0D element already exists.
+ * \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
+ */
+//================================================================================
+
+void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
+ TIDSortedElemSet& all0DElems )
+{
+ SMDS_ElemIteratorPtr elemIt;
+ vector< const SMDS_MeshElement* > allNodes;
+ if ( elements.empty() )
+ {
+ allNodes.reserve( GetMeshDS()->NbNodes() );
+ elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
+ while ( elemIt->more() )
+ allNodes.push_back( elemIt->next() );
+
+ elemIt = elemSetIterator( allNodes );
+ }
+ else
+ {
+ elemIt = elemSetIterator( elements );
+ }
+
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* e = elemIt->next();
+ SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
+ while ( nodeIt->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() );
+ }
+ }
+ }
+}
+
//=======================================================================
//function : FindShape
//purpose : Return an index of the shape theElem is on
}
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.
+//function : nbEdgeConnectivity
+//purpose : return number of the edges connected with the theNode.
// if theEdges has connections with the other type of the
-// elements, return -1
+// elements, return -1
//=======================================================================
+
static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
{
- SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
- int nb=0;
- while(elemIt->more()) {
- elemIt->next();
- nb++;
- }
- return nb;
+ // SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
+ // int nb=0;
+ // while(elemIt->more()) {
+ // elemIt->next();
+ // nb++;
+ // }
+ // return nb;
+ return theNode->NbInverseElements();
}
-
//=======================================================================
-//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)
+//function : getNodesFromTwoTria
+//purpose :
//=======================================================================
-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;
}
// 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_TNodeXYZ( nodes[3] ) +
+ SMESH_TNodeXYZ( nodes[4] ) +
+ SMESH_TNodeXYZ( 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;
}
//=======================================================================
// 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)
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_VtkVolume* aPolyedre =
+ dynamic_cast<const SMDS_VtkVolume*>( 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);
+ const int nbFaces = aPolyedre->NbFaces();
+ vector<const SMDS_MeshNode *> poly_nodes;
+ vector<int> quantities (nbFaces);
- // reverse each face of the polyedre
- for (int iface = 1; iface <= nbFaces; iface++) {
- int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
- quantities[iface - 1] = nbFaceNodes;
+ // reverse each face of the polyedre
+ for (int iface = 1; iface <= nbFaces; iface++) {
+ int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+ quantities[iface - 1] = nbFaceNodes;
- for (inode = nbFaceNodes; inode >= 1; inode--) {
- const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
- poly_nodes.push_back(curNode);
- }
+ for (inode = nbFaceNodes; inode >= 1; inode--) {
+ const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
+ poly_nodes.push_back(curNode);
}
-
- return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
-
- }
- 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 orientated according to
+ * \param theFace - one of \a theFaces that sould be oriented according to
* \a theDirection and whose orientation defines orientation of other faces
* \return number of reoriented faces.
*/
// 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 );
// Orient other faces
- set< const SMDS_MeshElement* > startFaces;
+ set< const SMDS_MeshElement* > startFaces, visitedFaces;
TIDSortedElemSet avoidSet;
set< SMESH_TLink > checkedLinks;
pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
theFaces.erase( theFace );
startFaces.insert( theFace );
+ int nodeInd1, nodeInd2;
+ const SMDS_MeshElement* otherFace;
+ vector< const SMDS_MeshElement* > facesNearLink;
+ vector< std::pair< int, int > > nodeIndsOfFace;
+
set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
- while ( startFace != startFaces.end() )
+ while ( !startFaces.empty() )
{
+ startFace = startFaces.begin();
theFace = *startFace;
- const int nbNodes = theFace->NbCornerNodes();
+ startFaces.erase( startFace );
+ if ( !visitedFaces.insert( theFace ).second )
+ continue;
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
{
link.second = theFace->GetNode(( i+1 ) % nbNodes );
{
// link has already been checked and won't be encountered more
// if the group (theFaces) is manifold
- checkedLinks.erase( linkIt_isNew.first );
+ //checkedLinks.erase( linkIt_isNew.first );
}
else
{
- int nodeInd1, nodeInd2;
- const SMDS_MeshElement* otherFace = FindFaceInSet( link.first, link.second,
- theFaces, avoidSet,
- & nodeInd1, & nodeInd2);
+ facesNearLink.clear();
+ nodeIndsOfFace.clear();
+ while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
+ theFaces, avoidSet,
+ &nodeInd1, &nodeInd2 )))
+ if ( otherFace != theFace)
+ {
+ facesNearLink.push_back( otherFace );
+ nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
+ avoidSet.insert( otherFace );
+ }
+ if ( facesNearLink.size() > 1 )
+ {
+ // NON-MANIFOLD mesh shell !
+ // select a face most co-directed with theFace,
+ // other faces won't be visited this time
+ gp_XYZ NF, NOF;
+ SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
+ double proj, maxProj = -1;
+ for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
+ SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
+ if (( proj = Abs( NF * NOF )) > maxProj ) {
+ maxProj = proj;
+ otherFace = facesNearLink[i];
+ nodeInd1 = nodeIndsOfFace[i].first;
+ nodeInd2 = nodeIndsOfFace[i].second;
+ }
+ }
+ // not to visit rejected faces
+ for ( size_t i = 0; i < facesNearLink.size(); ++i )
+ if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
+ visitedFaces.insert( facesNearLink[i] );
+ }
+ else if ( facesNearLink.size() == 1 )
+ {
+ otherFace = facesNearLink[0];
+ nodeInd1 = nodeIndsOfFace.back().first;
+ nodeInd2 = nodeIndsOfFace.back().second;
+ }
if ( otherFace && otherFace != theFace)
{
- // link must be reversed in otherFace if orientation ot otherFace
+ // link must be reverse in otherFace if orientation ot otherFace
// is same as that of theFace
if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
{
- // cout << "Reorient " << otherFace->GetID() << " near theFace=" <<theFace->GetID()
- // << " \tlink( " << link.first->GetID() << " " << link.second->GetID() << endl;
nbReori += Reorient( otherFace );
}
startFaces.insert( otherFace );
- if ( theFaces.size() > 1 ) // leave 1 face to prevent finding not selected faces
- theFaces.erase( otherFace );
}
}
- std::swap( link.first, link.second );
+ std::swap( link.first, link.second ); // reverse the link
}
- startFaces.erase( startFace );
- startFace = startFaces.begin();
}
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 = 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 :
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- MESSAGE( "::QuadToTri()" );
-
if ( !theCrit.get() )
return false;
SMESH_MesherHelper helper( *GetMesh() );
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 liner 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 ) {
// tr1 + tr2 is better
newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
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
// 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 splitted. 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;
+ SMESH_MesherHelper helper( *GetMesh() );
+ helper.SetElementsOnShape( true );
- if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
- return -1;
+ SMDS_ElemIteratorPtr faceIt;
+ if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
+ else faceIt = elemSetIterator( theElems );
- if( theQuad->NbNodes()==4 ||
- (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
+ bool checkUV;
+ gp_XY uv [9]; uv[8] = gp_XY(0,0);
+ gp_XYZ xyz[9];
+ vector< const SMDS_MeshNode* > nodes;
+ SMESHDS_SubMesh* subMeshDS;
+ TopoDS_Face F;
+ Handle(Geom_Surface) surface;
+ TopLoc_Location loc;
- // 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() );
+ while ( faceIt->more() )
+ {
+ const SMDS_MeshElement* quad = faceIt->next();
+ if ( !quad || quad->NbCornerNodes() != 4 )
+ continue;
+
+ // get a surface the quad is on
+
+ if ( quad->getshapeId() < 1 )
+ {
+ F.Nullify();
+ helper.SetSubShape( 0 );
+ subMeshDS = 0;
}
- // compare two sets of possible triangles
- double aBadRate1, aBadRate2; // to what extent a set is bad
+ 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_TNodeXYZ( 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.Append( nCentral );
+ }
+
+ // create 4 triangles
+
+ helper.SetIsQuadratic ( nodes.size() > 4 );
+ helper.SetIsBiQuadratic( nodes.size() == 9 );
+ if ( helper.GetIsQuadratic() )
+ helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
+
+ 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 );
+ ReplaceElemInGroups( tria, quad, GetMeshDS() );
+ myLastCreatedElems.Append( tria );
+ }
+ }
+}
+
+//=======================================================================
+//function : BestSplit
+//purpose : Find better diagonal for cutting.
+//=======================================================================
+
+int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
+ SMESH::Controls::NumericalFunctorPtr theCrit)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ 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() );
+ }
+ // compare two sets of possible triangles
+ double aBadRate1, aBadRate2; // to what extent a set is bad
SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
-
+ // 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) // tr1 + tr2 is better
return 1; // diagonal 1-3
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; }
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 );
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,
// 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)
+ {
+ // 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;
+ }
+ return to4methods[iF];
+ }
+ // else if ( methodFlags == HEXA_TO_2_PRISMS )
+
+ TSplitMethod method;
+
+ 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 compliancy 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;
}
} // 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;
-
+
SMESH_SequenceOfElemPtr newNodes, newElems;
// 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 )
{
}
}
- // 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.Append( 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.Append( 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, false );
+ 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
}
}
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.Append( 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 );
-//================================================================================
-/*!
- * \brief Replace elemToRm by elemToAdd in the all groups
- */
-//================================================================================
+ delete searcher;
-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 ] );
- }
+ if ( !startHex )
+ throw SALOME_Exception( THIS_METHOD "startHex not found");
}
-}
-
-//=======================================================================
-//function : QuadToTri
-//purpose : Cut quadrangles into triangles.
-// theCrit is used to select a diagonal to cut
-//=======================================================================
-bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
- const bool the13Diag)
-{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ // Select a facet of startHex by theFacetNormal
- MESSAGE( "::QuadToTri()" );
+ 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");
- SMESHDS_Mesh * aMesh = GetMeshDS();
+ // Fill theFacets starting from facetID of startHex
- Handle(Geom_Surface) surface;
- SMESH_MesherHelper helper( *GetMesh() );
+ // facets used for seach of volumes adjacent to already treated ones
+ typedef pair< TFacetOfElem::iterator, int > TElemFacets;
+ typedef map< TVolumeFaceKey, TElemFacets > TFacetMap;
+ TFacetMap facetsToCheck;
- 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;
+ set<const SMDS_MeshNode*> facetNodes;
+ const SMDS_MeshElement* curHex;
- if(elem->NbNodes()==4) {
- // retrieve element nodes
- const SMDS_MeshNode* aNodes [4];
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- int i = 0;
- while ( itN->more() )
- aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+ const bool allHex = ((int) theHexas.size() == myMesh->NbHexas() );
- int aShapeId = FindShape( elem );
- const SMDS_MeshElement* newElem1 = 0;
- const SMDS_MeshElement* newElem2 = 0;
- if ( the13Diag ) {
- newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
+ 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;
+
+ pair< TFacetOfElem::iterator, bool > facetIt2isNew =
+ theFacets.insert( make_pair( curHex, curFacet ));
+ if ( !facetIt2isNew.second )
+ break;
+
+ // 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)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ MESSAGE( "::QuadToTri()" );
+
+ SMESHDS_Mesh * aMesh = GetMeshDS();
+
+ Handle(Geom_Surface) surface;
+ SMESH_MesherHelper helper( *GetMesh() );
+
+ TIDSortedElemSet::iterator itElem;
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+ {
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->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() )
+ aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+
+ int aShapeId = FindShape( elem );
+ const SMDS_MeshElement* newElem1 = 0;
+ const SMDS_MeshElement* newElem2 = 0;
+ if ( the13Diag ) {
+ newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
}
else {
myLastCreatedElems.Append(newElem2);
// put a new triangle on the same shape and add to the same groups
if ( aShapeId )
- {
- aMesh->SetMeshElementOnShape( newElem1, aShapeId );
- aMesh->SetMeshElementOnShape( newElem2, aShapeId );
- }
+ {
+ 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.Append(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);
// 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 );
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
}
// 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);
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]);
+ 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.Append(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);
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]);
+ 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.Append(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] );
}
}
const SMDS_MeshElement* elem = elemIt->next();
if(elem->GetType() == SMDSAbs_0DElement)
continue;
-
+
SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
if ( elem->GetType() == SMDSAbs_Volume )
{
if ( projector.IsDone() ) {
double u, v, 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 );
SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
while ( fIt->more() ) {
const SMDS_MeshElement* face = fIt->next();
- theElems.insert( face );
+ theElems.insert( theElems.end(), face );
}
}
// get all face ids theElems are on
// 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 );
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
// 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_TNodeXYZ( 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 )
+ // if ( posType != SMDS_TOP_3DSPACE )
+ // dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
+ // if ( dist2 < dist1 )
uv = newUV;
}
}
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++;
}
// 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->interlacedNodesElemIterator() ),
+ 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_TNodeXYZ( nodes[i-1] ) + SMESH_TNodeXYZ( nodes[i+1] ));
}
+ if (( SMESH_TNodeXYZ( 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_TNodeXYZ pP = prevNodes[ iNotSame ];
+ SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
+ gp_XYZ extrDir( pN - pP ), faceNorm;
+ SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
- SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
- SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
- gp_XYZ extrDir( pN - pP ), faceNorm;
- SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
+ return faceNorm * extrDir < 0.0;
+ }
+
+ //================================================================================
+ /*!
+ * \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();
+ const int nbNodes = elem->NbNodes();
const int nbCorners = elem->NbCornerNodes();
- SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
+ SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
polyhedron creation !!! */
// Loop on elem nodes:
// find new nodes and detect same nodes indices
}
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] );
+ isSingleNode.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++ )
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]);
+ aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1],
+ prevNod[2], midlNod[1], nextNod[2] );
else // sames[0]==1
- aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
- midlNod[0], nextNod[2], prevNod[2]);
+ aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0],
+ prevNod[2], nextNod[2], midlNod[0]);
}
}
else if ( nbDouble == 3 )
}
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
midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
}
else if(nbSame==1) {
- // ---> pyramid + pentahedron - can not be created since it is needed
+ // ---> 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 );
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_MeshNode* node =
static_cast<const SMDS_MeshNode*>( nList->first );
+ if ( newElemsMap.count( node ))
+ continue; // node was extruded into edge
SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
int nbInitElems = 0;
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++ )
{
vecNewNodes[ 1 ]->second.back())) {
myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
vecNewNodes[ 1 ]->second.back()));
- srcElements.Append( myLastCreatedElems.Last() );
+ srcElements.Append( elem );
}
}
else {
myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
vecNewNodes[ 1 ]->second.back(),
vecNewNodes[ 2 ]->second.back()));
- srcElements.Append( myLastCreatedElems.Last() );
+ srcElements.Append( elem );
}
}
}
int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
- // check if a link is free
- if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
+ // check if a link n1-n2 is free
+ if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
hasFreeLinks = true;
- // make an edge and a ceiling for a new edge
- if ( !aMesh->FindEdge( n1, n2 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
+ // 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() );
}
n1 = vecNewNodes[ iNode ]->second.back();
n2 = vecNewNodes[ iNext ]->second.back();
if ( !aMesh->FindEdge( n1, n2 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
- srcElements.Append( myLastCreatedElems.Last() );
+ myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
+ srcElements.Append( 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( myLastCreatedElems.Last() );
+ srcElements.Append( 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( myLastCreatedElems.Last() );
+ srcElements.Append( 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 );
{
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, &polygon_nodes[0], nbn );
else
- AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
+ AddElement( polygon_nodes, polyFace.SetQuad( (*v)->IsQuadratic() ));
}
}
// 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 )
- {
- 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 )
+ 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->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 );
- while ( srcElements.Length() < myLastCreatedElems.Length() )
- srcElements.Append( myLastCreatedElems.Last() );
+ AddElement( nodeVec, anyFace.Init( elem ));
+
+ while ( srcElements.Length() < myLastCreatedElems.Length() )
+ srcElements.Append( 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,
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
+ setElemsFirst( 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.Append(newNode);
+ srcNodes.Append( 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 );
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 : ExtrusParam
+//purpose : standard construction
+//=======================================================================
+
+SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec& theStep,
+ const int theNbSteps,
+ const int theFlags,
+ const double theTolerance):
+ myDir( theStep ),
+ myFlags( theFlags ),
+ myTolerance( theTolerance ),
+ myElemsToUse( NULL )
+{
+ mySteps = new TColStd_HSequenceOfReal;
+ const double stepSize = theStep.Magnitude();
+ for (int i=1; i<=theNbSteps; i++ )
+ mySteps->Append( stepSize );
+
+ if (( theFlags & EXTRUSION_FLAG_SEW ) &&
+ ( theTolerance > 0 ))
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
+ }
+ else
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
+ }
+}
//=======================================================================
-//function : CreateNode
-//purpose :
+//function : ExtrusParam
+//purpose : steps are given explicitly
//=======================================================================
-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_Dir& theDir,
+ Handle(TColStd_HSequenceOfReal) theSteps,
+ const int theFlags,
+ const double theTolerance):
+ myDir( theDir ),
+ mySteps( theSteps ),
+ myFlags( theFlags ),
+ myTolerance( theTolerance ),
+ myElemsToUse( NULL )
+{
+ if (( theFlags & EXTRUSION_FLAG_SEW ) &&
+ ( theTolerance > 0 ))
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
+ }
+ else
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
+ }
+}
+
+//=======================================================================
+//function : ExtrusParam
+//purpose : for extrusion by normal
+//=======================================================================
+
+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 )
+{
+ for (int i = 0; i < theNbSteps; i++ )
+ mySteps->Append( theStepSize );
+
+ if ( theDim == 1 )
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal1D;
+ }
+ else
+ {
+ myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal2D;
+ }
+}
+
+//=======================================================================
+//function : ExtrusParam::SetElementsToUse
+//purpose : stores elements to use for extrusion by normal, depending on
+// state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag
+//=======================================================================
+
+void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems )
{
- // myLastCreatedElems.Clear();
- // myLastCreatedNodes.Clear();
+ myElemsToUse = ToUseInpElemsOnly() ? & elems : 0;
+}
+
+//=======================================================================
+//function : ExtrusParam::beginStepIter
+//purpose : prepare iteration on steps
+//=======================================================================
+
+void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes )
+{
+ myWithMediumNodes = withMediumNodes;
+ myNextStep = 1;
+ myCurSteps.clear();
+}
+//=======================================================================
+//function : ExtrusParam::moreSteps
+//purpose : are there more steps?
+//=======================================================================
- gp_Pnt P1(x,y,z);
- SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
+bool SMESH_MeshEditor::ExtrusParam::moreSteps()
+{
+ return myNextStep <= mySteps->Length() || !myCurSteps.empty();
+}
+//=======================================================================
+//function : ExtrusParam::nextStep
+//purpose : returns the next step
+//=======================================================================
- // 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);
+double SMESH_MeshEditor::ExtrusParam::nextStep()
+{
+ 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();
}
- 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;
+ return res;
+}
+
+//=======================================================================
+//function : ExtrusParam::makeNodesByDir
+//purpose : create nodes for standard extrusion
+//=======================================================================
+
+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_TNodeXYZ( srcNode );
+
+ 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 );
+ }
+ return nbNodes;
+}
+
+//=======================================================================
+//function : ExtrusParam::makeNodesByDirAndSew
+//purpose : create nodes for standard extrusion with sewing
+//=======================================================================
+
+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_TNodeXYZ( srcNode );
+
+ int nbNodes = 0;
+ for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
+ {
+ P1 += myDir.XYZ() * nextStep();
+
+ // try to search in sequence of existing nodes
+ // if myNodes.Length()>0 we 'nave to use given sequence
+ // else - use all nodes of mesh
+ const SMDS_MeshNode * node = 0;
+ if ( myNodes.Length() > 0 ) {
+ int i;
+ for(i=1; i<=myNodes.Length(); i++) {
+ gp_XYZ P2 = SMESH_TNodeXYZ( myNodes.Value(i) );
+ if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
+ {
+ node = myNodes.Value(i);
+ break;
+ }
+ }
+ }
+ else {
+ SMDS_NodeIteratorPtr itn = mesh->nodesIterator();
+ while(itn->more()) {
+ SMESH_TNodeXYZ P2( itn->next() );
+ if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
+ {
+ node = P2._node;
+ break;
+ }
+ }
+ }
+
+ if ( !node )
+ node = mesh->AddNode( P1.X(), P1.Y(), P1.Z() );
+
+ newNodes.push_back( node );
+
+ } // loop on steps
+
+ return nbNodes;
+}
+
+//=======================================================================
+//function : ExtrusParam::makeNodesByNormal2D
+//purpose : create nodes for extrusion using normals of faces
+//=======================================================================
+
+int SMESH_MeshEditor::ExtrusParam::
+makeNodesByNormal2D( SMESHDS_Mesh* mesh,
+ const SMDS_MeshNode* srcNode,
+ std::list<const SMDS_MeshNode*> & newNodes,
+ const bool makeMediumNodes)
+{
+ const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL );
+
+ gp_XYZ p = SMESH_TNodeXYZ( 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_TNodeXYZ( nIt->next() );
+ baryCenters.push_back( bc / nbN );
+ }
}
}
- // create new node and return it
- const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
- //myLastCreatedNodes.Append(NewNode);
- return NewNode;
+ if ( norms.empty() ) return 0;
+
+ double normSize = avgNorm.Modulus();
+ if ( normSize < std::numeric_limits<double>::min() )
+ return 0;
+
+ if ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ) // extrude along avgNorm
+ {
+ myDir = avgNorm;
+ return makeNodesByDir( mesh, srcNode, newNodes, makeMediumNodes );
+ }
+
+ avgNorm /= normSize;
+
+ int nbNodes = 0;
+ for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
+ {
+ gp_XYZ pNew = p;
+ double stepSize = nextStep();
+
+ 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;
+
+ // 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;
+ }
+ }
+ else
+ {
+ pNew += stepSize * avgNorm;
+ }
+ p = pNew;
+
+ const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
+ newNodes.push_back( newNode );
+ }
+ return nbNodes;
}
+//=======================================================================
+//function : ExtrusParam::makeNodesByNormal1D
+//purpose : create nodes for extrusion using normals of edges
+//=======================================================================
+
+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;
+}
//=======================================================================
//function : ExtrusionSweep
//=======================================================================
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::ExtrusionSweep (TIDSortedElemSet theElems[2],
+ const gp_Vec& theStep,
+ const int theNbSteps,
+ TTElemOfElemListMap& newElemsMap,
+ const int theFlags,
+ const double theTolerance)
{
- 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);
+ ExtrusParam aParams( theStep, theNbSteps, theFlags, theTolerance );
+ return ExtrusionSweep( theElems, aParams, newElemsMap );
}
//=======================================================================
SMESH_MeshEditor::PGroupIDs
-SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
- ExtrusParam& theParams,
- TElemOfElemListMap& newElemsMap,
- const bool theMakeGroups,
- const int theFlags,
- const double theTolerance)
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2],
+ ExtrusParam& theParams,
+ TTElemOfElemListMap& newElemsMap)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
// source elements for each generated one
SMESH_SequenceOfElemPtr srcElems, srcNodes;
- SMESHDS_Mesh* aMesh = GetMeshDS();
+ //SMESHDS_Mesh* aMesh = GetMeshDS();
- int nbsteps = theParams.mySteps->Length();
+ setElemsFirst( theElemSets );
+ const int nbSteps = theParams.NbSteps();
+ theParams.SetElementsToUse( theElemSets[0] );
TNodeOfNodeListMap mapNewNodes;
//TNodeOfNodeVecMap mapNewNodes;
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;
+ 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;
- vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
- newNodesItVec.reserve( elem->NbNodes() );
+ const size_t nbNodes = elem->NbNodes();
+ vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+ newNodesItVec.reserve( 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() );
- TNodeOfNodeListMap::iterator nIt =
- mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
- list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
- if ( listNewNodes.empty() )
+ // loop on elem nodes
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
{
- // make new nodes
-
- // check if we are to create medium nodes between corner ones
- bool needMediumNodes = false;
- if ( isQuadraticMesh )
+ // 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() )
{
- 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
- double coord[] = { node->X(), node->Y(), node->Z() };
- for ( int i = 0; i < nbsteps; i++ )
- {
- if ( needMediumNodes ) // create a medium node
+ // check if we are to create medium nodes between corner ones
+ bool needMediumNodes = false;
+ if ( isQuadraticMesh )
{
- 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 );
+ 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;
}
- else {
- const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
- myLastCreatedNodes.Append(newNode);
+ }
+ // 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.Append( *newNodesIt );
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 );
+ else
+ {
+ break; // newNodesItVec will be shorter than nbNodes
}
}
+ newNodesItVec.push_back( nIt );
}
- newNodesItVec.push_back( nIt );
+ // make new elements
+ if ( newNodesItVec.size() == nbNodes )
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems );
}
- // make new elements
- sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
}
- if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
- makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
+ if ( theParams.ToMakeBoundary() ) {
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems );
}
PGroupIDs newGroupIDs;
- if ( theMakeGroups )
+ if ( theParams.ToMakeGroups() )
newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
return newGroupIDs;
//purpose :
//=======================================================================
SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
SMESH_subMesh* theTrack,
const SMDS_MeshNode* theN1,
const bool theHasAngles,
TNodeOfNodeListMap mapNewNodes;
// 1. Check data
- aNbE = theElements.size();
+ aNbE = theElements[0].size() + theElements[1].size();
// nothing to do
if ( !aNbE )
return EXTR_NO_ELEMENTS;
ASSERT( theTrack );
SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
+ if ( !pSubMeshDS )
+ return ExtrusionAlongTrack( theElements, theTrack->GetFather(), theN1,
+ theHasAngles, theAngles, theLinearVariation,
+ theHasRefPoint, theRefPoint, theMakeGroups );
aItE = pSubMeshDS->GetElements();
while ( aItE->more() ) {
if( aS.ShapeType() == TopAbs_EDGE ) {
aTrackEdge = TopoDS::Edge( aS );
// the Edge must not be degenerated
- if ( BRep_Tool::Degenerated( aTrackEdge ) )
+ if ( SMESH_Algo::isDegenerated( aTrackEdge ) )
return EXTR_BAD_PATH_SHAPE;
TopExp::Vertices( aTrackEdge, aV1, aV2 );
aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
int startNid = theN1->GetID();
TColStd_MapOfInteger UsedNums;
-
+
int NbEdges = Edges.Length();
int i = 1;
for(; i<=NbEdges; i++) {
//purpose :
//=======================================================================
SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
SMESH_Mesh* theTrack,
const SMDS_MeshNode* theN1,
const bool theHasAngles,
TNodeOfNodeListMap mapNewNodes;
// 1. Check data
- aNbE = theElements.size();
+ aNbE = theElements[0].size() + theElements[1].size();
// nothing to do
if ( !aNbE )
return EXTR_NO_ELEMENTS;
const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
- if( aS == SMESH_Mesh::PseudoShape() ) {
+ if ( !theTrack->HasShapeToMesh() ) {
//Mesh without shape
const SMDS_MeshNode* currentNode = NULL;
const SMDS_MeshNode* prevNode = theN1;
if( !theTrack->GetMeshDS()->Contains(theN1) ) {
return EXTR_BAD_STARTING_NODE;
}
-
+
conn = nbEdgeConnectivity(theN1);
- if(conn > 2)
+ if( conn != 1 )
return EXTR_PATH_NOT_EDGE;
aItE = theN1->GetInverseElementIterator();
if(currentNode == prevNode)
currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
aNodesList.push_back(currentNode);
- } else {
+ } 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++;
conn = nbEdgeConnectivity(currentNode);
if(conn > 2) {
- return EXTR_PATH_NOT_EDGE;
+ return EXTR_PATH_NOT_EDGE;
}else if( conn == 1 && nbEdges > 0 ) {
//End of the path
nbEdges++;
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));
+ for ( size_t i = 1; i < aNodesList.size(); i++ )
+ {
+ gp_Pnt p1 = SMESH_TNodeXYZ( aNodesList[i-1] );
+ gp_Pnt p2 = SMESH_TNodeXYZ( aNodesList[i] );
+ TopoDS_Edge e = BRepBuilderAPI_MakeEdge( p1, p2 );
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();
-
+ 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();
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 ) );
+ gp_Dir Dnew( 0.5 * ( D1.XYZ() + D2.XYZ() ));
PP1.SetTangent(Dnew);
fullList.push_back(PP1);
itPP++;
fullList.pop_back();
}
fullList.push_back(PP1);
-
+
} // Sub-shape for the Pattern must be an Edge or Wire
- else if( aS.ShapeType() == TopAbs_EDGE ) {
+ else if ( aS.ShapeType() == TopAbs_EDGE )
+ {
aTrackEdge = TopoDS::Edge( aS );
// the Edge must not be degenerated
- if ( BRep_Tool::Degenerated( aTrackEdge ) )
+ if ( SMESH_Algo::isDegenerated( aTrackEdge ) )
return EXTR_BAD_PATH_SHAPE;
TopExp::Vertices( aTrackEdge, aV1, aV2 );
- aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN1 = aItN->next();
- aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN2 = aItN->next();
+ const SMDS_MeshNode* aN1 = SMESH_Algo::VertexNode( aV1, pMeshDS );
+ const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
// starting node must be aN1 or aN2
if ( !( aN1 == theN1 || aN2 == theN1 ) )
return EXTR_BAD_STARTING_NODE;
TopExp_Explorer eExp(aS, TopAbs_EDGE);
for(; eExp.More(); eExp.Next()) {
TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
- if( BRep_Tool::Degenerated(E) ) continue;
+ if( SMESH_Algo::isDegenerated(E) ) continue;
SMESH_subMesh* SM = theTrack->GetSubMesh(E);
if(SM) {
LSM.push_back(SM);
}
}
list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
- int startNid = theN1->GetID();
+ TopoDS_Vertex aVprev;
TColStd_MapOfInteger UsedNums;
int NbEdges = Edges.Length();
int i = 1;
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;
+ 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 = SMESH_Algo::VertexNode( aV1, pMeshDS );
+ const SMDS_MeshNode* aN2 = SMESH_Algo::VertexNode( aV2, pMeshDS );
+ // 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_MeshNode* pNode = aItN->next();
const SMDS_EdgePosition* pEPos =
static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
double aT = pEPos->GetUParameter();
}
list<SMESH_MeshEditor_PathPoint> LPP;
//Extrusion_Error err =
- MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+ MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, 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();
+ 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 );
- }
+ list<SMESH_MeshEditor_PathPoint>& firstList = *itLLPP;
+ fullList.splice( fullList.end(), firstList );
+
SMESH_MeshEditor_PathPoint PP1 = fullList.back();
fullList.pop_back();
itLLPP++;
for(; itLLPP!=LLPPs.end(); itLLPP++) {
- list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
- itPP = currList.begin();
+ list<SMESH_MeshEditor_PathPoint>& currList = *itLLPP;
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 ) );
+ gp_Dir Dnew( D1.XYZ() + D2.XYZ() );
PP1.SetTangent(Dnew);
fullList.push_back(PP1);
- itPP++;
- for(; itPP!=currList.end(); itPP++) {
- fullList.push_back( *itPP );
- }
+ fullList.splice( fullList.end(), currList, ++currList.begin(), currList.end() );
PP1 = fullList.back();
fullList.pop_back();
}
//purpose : auxilary for ExtrusionAlongTrack
//=======================================================================
SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
- const TopoDS_Edge& aTrackEdge,
- bool FirstIsStart,
+SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
+ const TopoDS_Edge& aTrackEdge,
+ bool FirstIsStart,
list<SMESH_MeshEditor_PathPoint>& LPP)
{
Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
aL2 = aVec.SquareMagnitude();
if ( aL2 < aTolVec2 )
return EXTR_CANT_GET_TANGENT;
- gp_Dir aTgt( aVec );
+ gp_Dir aTgt( FirstIsStart ? aVec : -aVec );
aPP.SetPnt( aP3D );
aPP.SetTangent( aTgt );
aPP.SetParameter( aT );
//purpose : auxilary for ExtrusionAlongTrack
//=======================================================================
SMESH_MeshEditor::Extrusion_Error
-SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
+SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets[2],
list<SMESH_MeshEditor_PathPoint>& fullList,
- const bool theHasAngles,
- list<double>& theAngles,
- const bool theLinearVariation,
- const bool theHasRefPoint,
- const gp_Pnt& theRefPoint,
- const bool theMakeGroups)
+ 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);
+ const int aNbTP = fullList.size();
+
// Angles
- if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
+ if( theHasAngles && !theAngles.empty() && 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;
+ vector<SMESH_MeshEditor_PathPoint> aPPs;
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;
+ list<double>::iterator itAngles = theAngles.begin();
+ aPPs.push_back( *itPP++ );
+ for( ; itPP != fullList.end(); itPP++) {
+ aPPs.push_back( *itPP );
+ if ( theHasAngles && itAngles != theAngles.end() )
+ aPPs.back().SetAngle( *itAngles++ );
}
- TNodeOfNodeListMap mapNewNodes;
+ TNodeOfNodeListMap mapNewNodes;
TElemOfVecOfNnlmiMap mapElemNewNodes;
- TElemOfElemListMap newElemsMap;
+ TTElemOfElemListMap newElemsMap;
TIDSortedElemSet::iterator itElem;
- double aX, aY, aZ;
- int aNb;
- SMDSAbs_ElementType aTypeE;
// source elements for each generated one
SMESH_SequenceOfElemPtr srcElems, srcNodes;
// 3. Center of rotation aV0
gp_Pnt aV0 = theRefPoint;
- gp_XYZ aGC;
- if ( !theHasRefPoint ) {
- aNb = 0;
- aGC.SetCoord( 0.,0.,0. );
-
- itElem = theElements.begin();
- for ( ; itElem != theElements.end(); itElem++ ) {
- const SMDS_MeshElement* elem = *itElem;
-
- 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 ( !theHasRefPoint )
+ {
+ gp_XYZ aGC( 0.,0.,0. );
+ TIDSortedElemSet newNodes;
- if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
- list<const SMDS_MeshNode*> aLNx;
- mapNewNodes[node] = aLNx;
- //
- gp_XYZ aXYZ( aX, aY, aZ );
- aGC += aXYZ;
- ++aNb;
+ for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+ {
+ TIDSortedElemSet& theElements = theElemSets[ is2ndSet ];
+ itElem = theElements.begin();
+ for ( ; itElem != theElements.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 )
+ aGC += SMESH_TNodeXYZ( node );
}
}
}
- aGC /= aNb;
+ aGC /= newNodes.size();
aV0.SetXYZ( aGC );
} // if (!theHasRefPoint) {
- mapNewNodes.clear();
// 4. Processing the elements
SMESHDS_Mesh* aMesh = GetMeshDS();
+ list<const SMDS_MeshNode*> emptyList;
- 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;
-
- vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
- newNodesItVec.reserve( elem->NbNodes() );
-
- // loop on elem nodes
- int nodeIndex = -1;
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() )
+ setElemsFirst( theElemSets );
+ for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+ {
+ TIDSortedElemSet& theElements = theElemSets[ is2ndSet ];
+ for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ )
{
- ++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;
-
- // make new nodes
- aX = node->X(); aY = node->Y(); aZ = node->Z();
-
- Standard_Real aAngle1x, aAngleT1T0, aTolAng;
- gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
- gp_Ax1 anAx1, anAxT1T0;
- gp_Dir aDT1x, aDT0x, aDT1T0;
-
- aTolAng=1.e-4;
-
- aV0x = aV0;
- aPN0.SetCoord(aX, aY, aZ);
-
- const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
- aP0x = aPP0.Pnt();
- aDT0x= aPP0.Tangent();
- //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
-
- for ( j = 1; j < aNbTP; ++j ) {
- const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
- aP1x = aPP1.Pnt();
- aDT1x = aPP1.Tangent();
- aAngle1x = aPP1.Angle();
-
- gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
- // Translation
- gp_Vec aV01x( aP0x, aP1x );
- aTrsf.SetTranslation( aV01x );
+ const SMDS_MeshElement* elem = *itElem;
- // traslated point
- aV1x = aV0x.Transformed( aTrsf );
- aPN1 = aPN0.Transformed( aTrsf );
+ vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+ newNodesItVec.reserve( elem->NbNodes() );
- // 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 );
+ // 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 = cast2Node( itN->next() );
+ TNodeOfNodeListMap::iterator nIt = mapNewNodes.insert( make_pair( node, emptyList )).first;
+ list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+ if ( listNewNodes.empty() )
+ {
+ // make new nodes
+ Standard_Real aAngle1x, aAngleT1T0, aTolAng;
+ gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
+ gp_Ax1 anAx1, anAxT1T0;
+ gp_Dir aDT1x, aDT0x, aDT1T0;
+
+ aTolAng=1.e-4;
+
+ aV0x = aV0;
+ aPN0 = SMESH_TNodeXYZ( node );
+
+ const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
+ aP0x = aPP0.Pnt();
+ aDT0x= aPP0.Tangent();
+
+ for ( int j = 1; j < aNbTP; ++j ) {
+ const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
+ aP1x = aPP1.Pnt();
+ aDT1x = aPP1.Tangent();
+ aAngle1x = aPP1.Angle();
+
+ gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
+ // Translation
+ gp_Vec aV01x( aP0x, aP1x );
+ aTrsf.SetTranslation( aV01x );
+
+ // traslated point
+ aV1x = aV0x.Transformed( aTrsf );
+ aPN1 = aPN0.Transformed( aTrsf );
+
+ // rotation 1 [ T1,T0 ]
+ aAngleT1T0=-aDT1x.Angle( aDT0x );
+ if (fabs(aAngleT1T0) > aTolAng)
+ {
+ aDT1T0=aDT1x^aDT0x;
+ anAxT1T0.SetLocation( aV1x );
+ anAxT1T0.SetDirection( aDT1T0 );
+ aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
- aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
- }
+ aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
+ }
- // rotation 2
- if ( theHasAngles ) {
- anAx1.SetLocation( aV1x );
- anAx1.SetDirection( aDT1x );
- aTrsfRot.SetRotation( anAx1, aAngle1x );
+ // rotation 2
+ if ( theHasAngles ) {
+ anAx1.SetLocation( aV1x );
+ anAx1.SetDirection( aDT1x );
+ aTrsfRot.SetRotation( anAx1, aAngle1x );
- aPN1 = aPN1.Transformed( aTrsfRot );
- }
+ aPN1 = aPN1.Transformed( aTrsfRot );
+ }
- // make new node
- //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);
+ // make new node
+ if ( elem->IsQuadratic() && !elem->IsMediumNode(node) )
+ {
+ // create additional node
+ gp_XYZ midP = 0.5 * ( aPN1.XYZ() + aPN0.XYZ() );
+ const SMDS_MeshNode* newNode = aMesh->AddNode( midP.X(), midP.Y(), midP.Z() );
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ }
+ const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.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 );
- aPN0 = aPN1;
- aP0x = aP1x;
- aV0x = aV1x;
- aDT0x = aDT1x;
+ aPN0 = aPN1;
+ aP0x = aP1x;
+ aV0x = aV1x;
+ aDT0x = aDT1x;
+ }
}
- }
-
- 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) ) {
+ else if( elem->IsQuadratic() && !elem->IsMediumNode(node) )
+ {
+ // if current elem is quadratic and current node is not medium
+ // we have to check - may be it is needed to insert additional nodes
list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
- if(listNewNodes.size()==aNbTP-1) {
+ if ((int) 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();
}
}
}
+
+ newNodesItVec.push_back( nIt );
}
- newNodesItVec.push_back( nIt );
+ // make new elements
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
}
- // 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 );
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], aNbTP-1, srcElems );
if ( theMakeGroups )
generateGroups( srcNodes, srcElems, "extruded");
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.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() );
+ }
+
+ // 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();
- if ( geomType == SMDSGeom_POINT ) continue; // node
+ 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_VtkVolume* aPolyedre = dynamic_cast<const SMDS_VtkVolume*>( 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 ( iNode != nbNodes )
- continue; // not all nodes transformed
-
- if ( theTargetMesh ) {
- myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
- srcElems.Append( elem );
- }
- else if ( theCopy ) {
- myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
- srcElems.Append( elem );
- }
- else {
- aMesh->ChangePolygonNodes(elem, poly_nodes);
- }
- }
- break;
-
- case SMDSGeom_POLYHEDRA: // ------------------ polyhedral volume
- {
- const SMDS_VtkVolume* aPolyedre =
- dynamic_cast<const SMDS_VtkVolume*>( elem );
- if (!aPolyedre) {
- MESSAGE("Warning: bad volumic element");
- continue;
- }
-
- 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
-
- 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;
-
- case SMDSGeom_BALL: // -------------------- Ball
- {
- if ( !theCopy && !theTargetMesh ) continue;
-
- TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
- if (nodeMapIt == nodeMap.end())
- continue; // not all nodes transformed
-
- 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 );
+ if ( nodeMapIt == nodeMap.end() )
+ allTransformed = false; // not all nodes transformed
+ else
+ nodes.push_back((*nodeMapIt).second);
}
+ if ( needReverse && allTransformed )
+ std::reverse( nodes.end() - nbFaceNodes, nodes.end() );
}
- break;
-
- default: // ----------------------- Regular elements
-
+ if ( !allTransformed )
+ continue; // not all nodes transformed
+ }
+ else // ----------------------- the rest element types
+ {
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;
+ const vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType(), nbNodes );
+ const vector<int>& i = needReverse ? iRev : iForw;
// find transformed nodes
- vector<const SMDS_MeshNode*> nodes(nbNodes);
- int iNode = 0;
+ size_t iNode = 0;
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
while ( itN->more() ) {
- const SMDS_MeshNode* node =
- static_cast<const SMDS_MeshNode*>( itN->next() );
+ const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
if ( nodeMapIt == nodeMap.end() )
break; // not all nodes transformed
}
if ( iNode != nbNodes )
continue; // not all nodes transformed
+ }
- if ( theTargetMesh ) {
- if ( SMDS_MeshElement* copy =
- targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
- myLastCreatedElems.Append( copy );
- srcElems.Append( elem );
- }
- }
- else if ( theCopy ) {
- if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
- srcElems.Append( elem );
- }
- else {
- // reverse element as it was reversed by transformation
- if ( nbNodes > 2 )
- aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
- }
- } // switch ( geomType )
+ if ( editor ) {
+ // copy in this or a new mesh
+ if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false )))
+ srcElems.Append( elem );
+ }
+ else {
+ // reverse element as it was reversed by transformation
+ if ( nbNodes > 2 )
+ aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+ }
} // loop on elements
+ if ( editor && editor != this )
+ myLastCreatedElems = editor->myLastCreatedElems;
+
PGroupIDs newGroupIDs;
if ( ( theMakeGroups && theCopy ) ||
( theMakeGroups && theTargetMesh ) )
- newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+ newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false );
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 append to names of new groups
+ * \param targetMesh - mesh to create groups in
+ * \param topPresent - is there "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 one
- typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
+ // 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;
vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
+ vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
// group names
set< string > groupNames;
- //
- SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
+
SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
- while ( groupIt->more() ) {
+ if ( !groupIt->more() ) return newGroupIDs;
+
+ int newGroupID = mesh->GetGroupIds().back()+1;
+ while ( groupIt->more() )
+ {
SMESH_Group * group = groupIt->next();
if ( !group ) continue;
SMESHDS_GroupBase* groupDS = group->GetGroupDS();
if ( !groupDS || groupDS->IsEmpty() ) continue;
- groupNames.insert( group->GetName() );
+ groupNames.insert ( group->GetName() );
groupDS->SetStoreName( group->GetName() );
- groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
+ const SMDSAbs_ElementType type = groupDS->GetType();
+ SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
+ SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
+ groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
+ orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
}
- // Groups creation
+ // Loop on nodes and elements to add them in new groups
- // loop on nodes and elements
+ 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() )
- throw SALOME_Exception(LOCALIZED("invalid args"));
+ throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
// loop on created elements
for (int iElem = 1; iElem <= elems.Length(); ++iElem )
continue;
}
list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
- if ( groupsOldNew.empty() ) {
+ if ( groupsOldNew.empty() ) { // no groups of this type at all
while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
++iElem; // skip all elements made by sourceElem
continue;
}
- // collect all elements made by sourceElem
- list< const SMDS_MeshElement* > resultElems;
+ // collect all elements made by the iElem-th sourceElem
+ resultElems.clear();
if ( const SMDS_MeshElement* resElem = elems( iElem ))
if ( resElem != sourceElem )
resultElems.push_back( resElem );
if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
if ( resElem != sourceElem )
resultElems.push_back( resElem );
- // do not generate element groups from node ones
-// if ( sourceElem->GetType() == SMDSAbs_Node &&
-// elems( iElem )->GetType() != SMDSAbs_Node )
-// continue;
- // add resultElems to groups made by ones the sourceElem belongs to
+ const SMDS_MeshElement* topElem = 0;
+ if ( isNodes ) // there must be a top element
+ {
+ topElem = resultElems.back();
+ resultElems.pop_back();
+ }
+ else
+ {
+ vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
+ for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
+ if ( (*resElemIt)->GetType() == sourceElem->GetType() )
+ {
+ topElem = *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 )
{
- SMESHDS_GroupBase* oldGroup = gOldNew->first;
- if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
+ SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
+ if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
{
- SMDS_MeshGroup* & newGroup = gOldNew->second;
- if ( !newGroup )// create a new group
- {
- // make a name
- string name = oldGroup->GetStoreName();
- if ( !targetMesh ) {
- name += "_";
- name += postfix;
- int nb = 0;
- while ( !groupNames.insert( name ).second ) // name exists
- {
- if ( nb == 0 ) {
- name += "_1";
- }
- else {
- TCollection_AsciiString nbStr(nb+1);
- name.resize( name.rfind('_')+1 );
- name += nbStr.ToCString();
- }
- ++nb;
- }
- }
- // make a group
- int id;
- SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
- name.c_str(), id );
- SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
- newGroup = & groupDS->SMDSGroup();
- newGroupIDs->push_back( id );
- }
-
// fill in a new group
- list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
+ SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
+ 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 )
+ {
+ SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
+ newTopGroup.Add( topElem );
+ }
}
}
} // loop on created elements
}// loop on nodes and elements
+ // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
+
+ list<int> topGrouIds;
+ for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
+ {
+ SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>();
+ SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
+ orderedOldNewGroups[i]->get<2>() };
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
+ if ( newGroupDS->IsEmpty() )
+ {
+ mesh->GetMeshDS()->RemoveGroup( newGroupDS );
+ }
+ else
+ {
+ // set group type
+ newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
+
+ // make a name
+ 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 += "_";
+ name += suffix;
+ int nb = 1;
+ while ( !groupNames.insert( name ).second ) // name exists
+ name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
+ }
+ else if ( isTop ) {
+ name += "_top";
+ }
+ newGroupDS->SetStoreName( name.c_str() );
+
+ // make a SMESH_Groups
+ mesh->AddGroup( newGroupDS );
+ if ( isTop )
+ topGrouIds.push_back( newGroupDS->GetID() );
+ else
+ newGroupIDs->push_back( newGroupDS->GetID() );
+ }
+ }
+ }
+ newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
+
return newGroupIDs;
}
//================================================================================
/*!
- * \brief Return list of group of nodes close to each other within theTolerance
- * Search among theNodes or in the whole mesh if theNodes is empty using
- * an Octree algorithm
+ * * \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();
- if ( theNodes.empty() )
- { // get all nodes in the mesh
- SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
- while ( nIt->more() )
- theNodes.insert( theNodes.end(),nIt->next());
- }
-
- SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
-}
+ if ( myMesh->NbEdges ( ORDER_QUADRATIC ) +
+ myMesh->NbFaces ( ORDER_QUADRATIC ) +
+ myMesh->NbVolumes( ORDER_QUADRATIC ) == 0 )
+ theSeparateCornersAndMedium = false;
+ TIDSortedNodeSet& corners = theNodes;
+ TIDSortedNodeSet medium;
-//=======================================================================
-/*!
- * \brief Implementation of search for the node closest to point
- */
-//=======================================================================
-
-struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
-{
- //---------------------------------------------------------------------
- /*!
- * \brief Constructor
- */
- SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
+ if ( theNodes.empty() ) // get all nodes in the mesh
{
- myMesh = ( SMESHDS_Mesh* ) theMesh;
-
- TIDSortedNodeSet nodes;
- if ( theMesh ) {
- SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
+ TIDSortedNodeSet* nodes[2] = { &corners, &medium };
+ SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
+ if ( theSeparateCornersAndMedium )
while ( nIt->more() )
- nodes.insert( nodes.end(), nIt->next() );
- }
- myOctreeNode = new SMESH_OctreeNode(nodes) ;
-
- // 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.;
+ {
+ 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() );
}
-
- //---------------------------------------------------------------------
- /*!
- * \brief Move node and update myOctreeNode accordingly
- */
- void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
+ else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes
{
- 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)
+ TIDSortedNodeSet::iterator nIt = corners.begin();
+ while ( nIt != corners.end() )
+ if ( SMESH_MesherHelper::IsMedium( *nIt ))
{
- SMESH_OctreeNode* tree = *trIt;
- if ( !tree->isLeaf() ) // put children to the queue
- {
- if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
- SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
- while ( cIt->more() )
- treeList.push_back( cIt->next() );
- }
- 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 );
+ medium.insert( medium.end(), *nIt );
+ corners.erase( nIt++ );
}
- }
- // 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
+ {
+ ++nIt;
}
- }
- return closestNode;
}
- //---------------------------------------------------------------------
- /*!
- * \brief Destructor
- */
- ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
-
- //---------------------------------------------------------------------
- /*!
- * \brief Return the node tree
- */
- const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
-
-private:
- SMESH_OctreeNode* myOctreeNode;
- SMESHDS_Mesh* myMesh;
- double myHalfLeafSize; // max size of a leaf box
-};
+ if ( !corners.empty() )
+ SMESH_OctreeNode::FindCoincidentNodes ( corners, &theGroupsOfNodes, theTolerance );
+ if ( !medium.empty() )
+ SMESH_OctreeNode::FindCoincidentNodes ( medium, &theGroupsOfNodes, theTolerance );
+}
//=======================================================================
-/*!
- * \brief Return SMESH_NodeSearcher
- */
+//function : SimplifyFace
+//purpose : split a chain of nodes into several closed chains
//=======================================================================
-SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
+int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
+ vector<const SMDS_MeshNode *>& poly_nodes,
+ vector<int>& quantities) const
{
- return new SMESH_NodeSearcherImpl( GetMeshDS() );
-}
+ int nbNodes = faceNodes.size();
-// ========================================================================
-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
+ if (nbNodes < 3)
+ return 0;
- //=======================================================================
- /*!
- * \brief Octal tree of bounding boxes of elements
- */
- //=======================================================================
+ set<const SMDS_MeshNode*> nodeSet;
- class ElementBndBoxTree : public SMESH_Octree
- {
- public:
-
- ElementBndBoxTree(const SMDS_Mesh& mesh,
- SMDSAbs_ElementType elemType,
- SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
- double tolerance = NodeRadius );
- void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
- void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
- 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* allocateOctreeChild() const { return new ElementBndBoxTree; }
- void buildChildrenData();
- Bnd_B3d* buildRootBox();
- private:
- //!< Bounding box of element
- struct ElementBox : public Bnd_B3d
- {
- const SMDS_MeshElement* _element;
- int _refCount; // an ElementBox can be included in several tree branches
- ElementBox(const SMDS_MeshElement* elem, double tolerance);
- };
- vector< ElementBox* > _elements;
- size_t _size;
- };
+ // get simple seq of nodes
+ vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
+ int iSimple = 0;
- //================================================================================
- /*!
- * \brief ElementBndBoxTree creation
- */
- //================================================================================
+ simpleNodes[iSimple++] = faceNodes[0];
+ for (int iCur = 1; iCur < nbNodes; iCur++) {
+ if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
+ simpleNodes[iSimple++] = faceNodes[iCur];
+ nodeSet.insert( faceNodes[iCur] );
+ }
+ }
+ int nbUnique = nodeSet.size();
+ int nbSimple = iSimple;
+ if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
+ nbSimple--;
+ iSimple--;
+ }
- ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
- :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
- {
- int nbElems = mesh.GetMeshInfo().NbElements( elemType );
- _elements.reserve( nbElems );
+ if (nbUnique < 3)
+ return 0;
- SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
- while ( elemIt->more() )
- _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
+ // 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)
- compute();
+ if (iSimple > 2) {
+ nbNew++;
+ quantities.push_back(iSimple);
+ for (int i = 0; i < iSimple; i++)
+ poly_nodes.push_back(simpleNodes[i]);
}
- //================================================================================
- /*!
- * \brief Destructor
- */
- //================================================================================
+ return nbNew;
+}
- ElementBndBoxTree::~ElementBndBoxTree()
- {
- for ( int i = 0; i < _elements.size(); ++i )
- if ( --_elements[i]->_refCount <= 0 )
- delete _elements[i];
- }
+//=======================================================================
+//function : MergeNodes
+//purpose : In each group, the cdr of nodes are substituted by the first one
+// in all elements.
+//=======================================================================
- //================================================================================
- /*!
- * \brief Return the maximal box
- */
- //================================================================================
+void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
+{
+ MESSAGE("MergeNodes");
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
- Bnd_B3d* ElementBndBoxTree::buildRootBox()
- {
- Bnd_B3d* box = new Bnd_B3d;
- for ( int i = 0; i < _elements.size(); ++i )
- box->Add( *_elements[i] );
- return box;
- }
+ SMESHDS_Mesh* aMesh = GetMeshDS();
- //================================================================================
- /*!
- * \brief Redistrubute element boxes among children
- */
- //================================================================================
+ 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
- void ElementBndBoxTree::buildChildrenData()
+ TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
+ for ( ; grIt != theGroupsOfNodes.end(); grIt++ )
{
- for ( int i = 0; i < _elements.size(); ++i )
+ 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++ )
{
- for (int j = 0; j < 8; j++)
+ const SMDS_MeshNode* nToRemove = *nIt;
+ nodeNodeMap.insert( make_pair( nToRemove, nToKeep ));
+ if ( nToRemove != nToKeep )
{
- if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
- {
- _elements[i]->_refCount++;
- ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
- }
+ 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);
}
- _elements[i]->_refCount--;
- }
- _size = _elements.size();
- SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
-
- for (int j = 0; j < 8; j++)
- {
- 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 );
}
}
+ // Change element nodes or remove an element
- //================================================================================
- /*!
- * \brief Return elements which can include the point
- */
- //================================================================================
+ set<const SMDS_MeshNode*> nodeSet;
+ vector< const SMDS_MeshNode*> curNodes, uniqueNodes;
+ vector<int> iRepl;
+ ElemFeatures elemType;
- void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
- TIDSortedElemSet& foundElems)
+ set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
+ for ( ; eIt != elems.end(); eIt++ )
{
- if ( getBox().IsOut( point.XYZ() ))
- return;
+ const SMDS_MeshElement* elem = *eIt;
+ const int nbNodes = elem->NbNodes();
+ const int aShapeId = FindShape( elem );
- if ( isLeaf() )
- {
- for ( int i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( point.XYZ() ))
- foundElems.insert( _elements[i]->_element );
- }
- else
+ nodeSet.clear();
+ 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() )
{
- for (int i = 0; i < 8; i++)
- ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
- }
- }
+ const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
- //================================================================================
- /*!
- * \brief Return elements which can be intersected by the line
- */
- //================================================================================
+ 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++;
+ }
- void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
- TIDSortedElemSet& foundElems)
- {
- if ( getBox().IsOut( line ))
- return;
+ // Analyse element topology after replacement
- if ( isLeaf() )
- {
- for ( int i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( line ))
- foundElems.insert( _elements[i]->_element );
- }
- else
+ bool isOk = true;
+ int nbUniqueNodes = nodeSet.size();
+ if ( nbNodes != nbUniqueNodes ) // some nodes stick
{
- for (int i = 0; i < 8; i++)
- ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
- }
- }
+ if (elem->IsPoly()) // Polygons and Polyhedral volumes
+ {
+ if (elem->GetType() == SMDSAbs_Face) // Polygon
+ {
+ elemType.Init( elem );
+ const bool isQuad = elemType.myIsQuad;
+ if ( isQuad )
+ SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
+ ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes );
- //================================================================================
- /*!
- * \brief Return elements from leaves intersecting the sphere
- */
- //================================================================================
+ // a polygon can divide into several elements
+ vector<const SMDS_MeshNode *> polygons_nodes;
+ vector<int> quantities;
+ int nbNew = SimplifyFace( curNodes, polygons_nodes, quantities );
+ if (nbNew > 0)
+ {
+ vector<const SMDS_MeshNode *> face_nodes;
+ int inode = 0;
+ for (int iface = 0; iface < nbNew; iface++)
+ {
+ 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 ));
- void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center,
- const double radius,
- TIDSortedElemSet& foundElems)
- {
- if ( getBox().IsOut( center, radius ))
- return;
+ SMDS_MeshElement* newElem = AddElement( face_nodes, elemType );
+ if ( aShapeId )
+ aMesh->SetMeshElementOnShape(newElem, aShapeId);
+ }
+ }
+ rmElemIds.push_back(elem->GetID());
- if ( isLeaf() )
- {
- for ( int i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( center, radius ))
- foundElems.insert( _elements[i]->_element );
- }
- else
- {
- for (int i = 0; i < 8; i++)
- ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
- }
- }
+ } // Polygon
- //================================================================================
- /*!
- * \brief Construct the element box
- */
- //================================================================================
-
- ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
- {
- _element = elem;
- _refCount = 1;
- SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
- while ( nIt->more() )
- Add( SMESH_TNodeXYZ( nIt->next() ));
- Enlarge( tolerance );
- }
-
-} // 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) {}
- };
-};
-
-ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
-{
- return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
- << ", _coincides="<<i._coincides << ")";
-}
-
-//=======================================================================
-/*!
- * \brief define tolerance for search
- */
-//=======================================================================
-
-double SMESH_ElementSearcherImpl::getTolerance()
-{
- if ( _tolerance < 0 )
- {
- const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
-
- _tolerance = 0;
- if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
- {
- double boxSize = _nodeSearcher->getTree()->maxSize();
- _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
- }
- else if ( _ebbTree && meshInfo.NbElements() > 0 )
- {
- double boxSize = _ebbTree->maxSize();
- _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
- }
- if ( _tolerance == 0 )
- {
- // define tolerance by size of a most complex element
- int complexType = SMDSAbs_Volume;
- while ( complexType > SMDSAbs_All &&
- meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
- --complexType;
- if ( complexType == SMDSAbs_All ) return 0; // empty mesh
- double elemSize;
- if ( complexType == int( SMDSAbs_Node ))
- {
- SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
- elemSize = 1;
- if ( meshInfo.NbNodes() > 2 )
- elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
- }
- else
- {
- SMDS_ElemIteratorPtr elemIt =
- _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
- const SMDS_MeshElement* elem = elemIt->next();
- SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
- SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
- elemSize = 0;
- while ( nodeIt->more() )
- {
- double dist = n1.Distance( cast2Node( nodeIt->next() ));
- elemSize = max( dist, elemSize );
- }
- }
- _tolerance = 1e-4 * elemSize;
- }
- }
- return _tolerance;
-}
-
-//================================================================================
-/*!
- * \brief Find intersection of the line and an edge of face and return parameter on line
- */
-//================================================================================
-
-bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
- const SMDS_MeshElement* face,
- const double tol,
- double & param)
-{
- int nbInts = 0;
- param = 0;
-
- GeomAPI_ExtremaCurveCurve anExtCC;
- Handle(Geom_Curve) lineCurve = new Geom_Line( line );
-
- int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
- for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
- {
- GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
- SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
- anExtCC.Init( lineCurve, edge);
- if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
- {
- Quantity_Parameter pl, pe;
- anExtCC.LowerDistanceParameters( pl, pe );
- param += pl;
- if ( ++nbInts == 2 )
- break;
- }
- }
- if ( nbInts > 0 ) param /= nbInts;
- return nbInts > 0;
-}
-//================================================================================
-/*!
- * \brief Find all faces belonging to the outer boundary of mesh
- */
-//================================================================================
-
-void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
-{
- if ( _outerFacesFound ) return;
-
- // Collect all outer faces by passing from one outer face to another via their links
- // and BTW find out if there are internal faces at all.
-
- // checked links and links where outer boundary meets internal one
- set< SMESH_TLink > visitedLinks, seamLinks;
-
- // links to treat with already visited faces sharing them
- list < TFaceLink > startLinks;
-
- // load startLinks with the first outerFace
- startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
- _outerFaces.insert( outerFace );
-
- TIDSortedElemSet emptySet;
- while ( !startLinks.empty() )
- {
- const SMESH_TLink& link = startLinks.front()._link;
- TIDSortedElemSet& faces = startLinks.front()._faces;
-
- outerFace = *faces.begin();
- // find other faces sharing the link
- const SMDS_MeshElement* f;
- while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
- faces.insert( f );
-
- // select another outer face among the found
- const SMDS_MeshElement* outerFace2 = 0;
- if ( faces.size() == 2 )
- {
- outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
- }
- else if ( faces.size() > 2 )
- {
- seamLinks.insert( link );
-
- // link direction within the outerFace
- gp_Vec n1n2( SMESH_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 )
- {
- _outerFaces.insert( outerFace );
- int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
- for ( int i = 0; i < nbNodes; ++i )
- {
- SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
- if ( visitedLinks.insert( link2 ).second )
- startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
- }
- }
- startLinks.pop_front();
- }
- _outerFacesFound = true;
-
- if ( !seamLinks.empty() )
- {
- // There are internal boundaries touching the outher one,
- // find all faces of internal boundaries in order to find
- // faces of boundaries of holes, if any.
-
- }
- else
- {
- _outerFaces.clear();
- }
-}
-
-//=======================================================================
-/*!
- * \brief Find elements of given type where the given point is IN or ON.
- * Returns nb of found elements and elements them-selves.
- *
- * 'ALL' type means elements of any type excluding nodes, balls and 0D elements
- */
-//=======================================================================
-
-int SMESH_ElementSearcherImpl::
-FindElementsByPoint(const gp_Pnt& point,
- SMDSAbs_ElementType type,
- vector< const SMDS_MeshElement* >& foundElements)
-{
- foundElements.clear();
-
- double tolerance = getTolerance();
-
- // =================================================================================
- if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball)
- {
- if ( !_nodeSearcher )
- _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
-
- const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
- if ( !closeNode ) return foundElements.size();
-
- if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
- return foundElements.size(); // to far from any node
-
- if ( type == SMDSAbs_Node )
- {
- foundElements.push_back( closeNode );
- }
- else
- {
- SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type );
- while ( elemIt->more() )
- foundElements.push_back( elemIt->next() );
- }
- }
- // =================================================================================
- else // elements more complex than 0D
- {
- if ( !_ebbTree || _elementType != type )
- {
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
- }
- TIDSortedElemSet suspectElems;
- _ebbTree->getElementsNearPoint( point, suspectElems );
- TIDSortedElemSet::iterator elem = suspectElems.begin();
- for ( ; elem != suspectElems.end(); ++elem )
- if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance ))
- foundElements.push_back( *elem );
- }
- return foundElements.size();
-}
-
-//=======================================================================
-/*!
- * \brief Find an element of given type most close to the given point
- *
- * WARNING: Only face search is implemeneted so far
- */
-//=======================================================================
-
-const SMDS_MeshElement*
-SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point,
- SMDSAbs_ElementType type )
-{
- const SMDS_MeshElement* closestElem = 0;
-
- 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 );
-
- 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;
- }
- }
- else
- {
- // NOT IMPLEMENTED SO FAR
- }
- return closestElem;
-}
-
-
-//================================================================================
-/*!
- * \brief Classify the given point in the closed 2D mesh
- */
-//================================================================================
-
-TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
-{
- double tolerance = getTolerance();
- if ( !_ebbTree || _elementType != SMDSAbs_Face )
- {
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
- }
- // Algo: analyse transition of a line starting at the point through mesh boundary;
- // try three lines parallel to axis of the coordinate system and perform rough
- // analysis. If solution is not clear perform thorough analysis.
-
- const int nbAxes = 3;
- gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
- map< double, TInters > paramOnLine2TInters[ nbAxes ];
- list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
- multimap< int, int > nbInt2Axis; // to find the simplest case
- for ( int axis = 0; axis < nbAxes; ++axis )
- {
- gp_Ax1 lineAxis( point, axisDir[axis]);
- gp_Lin line ( lineAxis );
-
- TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
- _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
-
- // Intersect faces with the line
-
- map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
- TIDSortedElemSet::iterator face = suspectFaces.begin();
- for ( ; face != suspectFaces.end(); ++face )
- {
- // get face plane
- gp_XYZ fNorm;
- if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
- gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
-
- // perform intersection
- IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
- if ( !intersection.IsDone() )
- continue;
- if ( intersection.IsInQuadric() )
- {
- tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
- }
- else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
- {
- gp_Pnt intersectionPoint = intersection.Point(1);
- if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance ))
- u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
- }
- }
- // Analyse intersections roughly
-
- int nbInter = u2inters.size();
- if ( nbInter == 0 )
- return TopAbs_OUT;
-
- double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
- if ( nbInter == 1 ) // not closed mesh
- return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
-
- if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
- return TopAbs_ON;
-
- if ( (f<0) == (l<0) )
- return TopAbs_OUT;
-
- int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
- int nbIntAfterPoint = nbInter - nbIntBeforePoint;
- if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
- return TopAbs_IN;
-
- nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
-
- if ( _outerFacesFound ) break; // pass to thorough analysis
-
- } // three attempts - loop on CS axes
-
- // Analyse intersections thoroughly.
- // We make two loops maximum, on the first one we only exclude touching intersections,
- // on the second, if situation is still unclear, we gather and use information on
- // position of faces (internal or outer). If faces position is already gathered,
- // we make the second loop right away.
-
- for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
- {
- multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
- for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
- {
- int axis = nb_axis->second;
- map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
-
- gp_Ax1 lineAxis( point, axisDir[axis]);
- gp_Lin line ( lineAxis );
-
- // add tangent intersections to u2inters
- double param;
- list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
- for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
- if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
- u2inters.insert(make_pair( param, *tgtInt ));
- tangentInters[ axis ].clear();
-
- // Count intersections before and after the point excluding touching ones.
- // If hasPositionInfo we count intersections of outer boundary only
-
- int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
- double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
- map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
- bool ok = ! u_int1->second._coincides;
- while ( ok && u_int1 != u2inters.end() )
- {
- double u = u_int1->first;
- bool touchingInt = false;
- if ( ++u_int2 != u2inters.end() )
- {
- // skip intersections at the same point (if the line passes through edge or node)
- int nbSamePnt = 0;
- while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
- {
- ++nbSamePnt;
- ++u_int2;
- }
-
- // skip tangent intersections
- int nbTgt = 0;
- const SMDS_MeshElement* prevFace = u_int1->second._face;
- while ( ok && u_int2->second._coincides )
- {
- if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
- ok = false;
- else
- {
- nbTgt++;
- u_int2++;
- ok = ( u_int2 != u2inters.end() );
- }
- }
- if ( !ok ) break;
-
- // skip intersections at the same point after tangent intersections
- if ( nbTgt > 0 )
- {
- double u2 = u_int2->first;
- ++u_int2;
- while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
- {
- ++nbSamePnt;
- ++u_int2;
- }
- }
- // decide if we skipped a touching intersection
- if ( nbSamePnt + nbTgt > 0 )
- {
- double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
- map< double, TInters >::iterator u_int = u_int1;
- for ( ; u_int != u_int2; ++u_int )
- {
- if ( u_int->second._coincides ) continue;
- double dot = u_int->second._faceNorm * line.Direction();
- if ( dot > maxDot ) maxDot = dot;
- if ( dot < minDot ) minDot = dot;
- }
- touchingInt = ( minDot*maxDot < 0 );
- }
- }
- if ( !touchingInt )
- {
- if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
- {
- if ( u < 0 )
- ++nbIntBeforePoint;
- else
- ++nbIntAfterPoint;
- }
- if ( u < f ) f = u;
- if ( u > l ) l = u;
- }
-
- u_int1 = u_int2; // to next intersection
-
- } // loop on intersections with one line
-
- if ( ok )
- {
- if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
- return TopAbs_ON;
-
- if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
- return TopAbs_OUT;
-
- if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
- return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
-
- if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
- return TopAbs_IN;
-
- if ( (f<0) == (l<0) )
- return TopAbs_OUT;
-
- if ( hasPositionInfo )
- return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
- }
- } // loop on intersections of the tree lines - thorough analysis
-
- if ( !hasPositionInfo )
- {
- // gather info on faces position - is face in the outer boundary or not
- map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
- findOuterBoundary( u2inters.begin()->second._face );
- }
-
- } // two attempts - with and w/o faces position info in the mesh
-
- return TopAbs_UNKNOWN;
-}
-
-//=======================================================================
-/*!
- * \brief Return elements possibly intersecting the line
- */
-//=======================================================================
-
-void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
- SMDSAbs_ElementType type,
- vector< const SMDS_MeshElement* >& foundElems)
-{
- if ( !_ebbTree || _elementType != type )
- {
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
- }
- TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
- _ebbTree->getElementsNearLine( line, suspectFaces );
- foundElems.assign( suspectFaces.begin(), suspectFaces.end());
-}
-
-//=======================================================================
-/*!
- * \brief Return SMESH_ElementSearcher
- */
-//=======================================================================
-
-SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
-{
- return new SMESH_ElementSearcherImpl( *GetMeshDS() );
-}
-
-//=======================================================================
-/*!
- * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
- */
-//=======================================================================
-
-SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
-{
- return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
-}
-
-//=======================================================================
-/*!
- * \brief Return true if the point is IN or ON of the element
- */
-//=======================================================================
-
-bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
-{
- if ( element->GetType() == SMDSAbs_Volume)
- {
- return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
- }
-
- // get ordered nodes
-
- vector< gp_XYZ > xyz;
- vector<const SMDS_MeshNode*> nodeList;
-
- SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
- if ( element->IsQuadratic() ) {
- if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
- nodeIt = f->interlacedNodesElemIterator();
- else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
- nodeIt = e->interlacedNodesElemIterator();
- }
- while ( nodeIt->more() )
- {
- const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
- xyz.push_back( SMESH_TNodeXYZ(node) );
- nodeList.push_back(node);
- }
-
- int i, nbNodes = element->NbNodes();
-
- if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
- {
- // compute face normal
- gp_Vec faceNorm(0,0,0);
- xyz.push_back( xyz.front() );
- nodeList.push_back( nodeList.front() );
- for ( i = 0; i < nbNodes; ++i )
- {
- gp_Vec edge1( xyz[i+1], xyz[i]);
- gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
- faceNorm += edge1 ^ edge2;
- }
- double normSize = faceNorm.Magnitude();
- if ( normSize <= tol )
- {
- // degenerated face: point is out if it is out of all face edges
- for ( i = 0; i < nbNodes; ++i )
- {
- SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
- if ( !IsOut( &edge, point, tol ))
- return false;
- }
- return true;
- }
- faceNorm /= normSize;
-
- // check if the point lays on face plane
- gp_Vec n2p( xyz[0], point );
- if ( fabs( n2p * faceNorm ) > tol )
- return true; // not on face plane
-
- // check if point is out of face boundary:
- // define it by closest transition of a ray point->infinity through face boundary
- // on the face plane.
- // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
- // to find intersections of the ray with the boundary.
- gp_Vec ray = n2p;
- gp_Vec plnNorm = ray ^ faceNorm;
- normSize = plnNorm.Magnitude();
- if ( normSize <= tol ) return false; // point coincides with the first node
- plnNorm /= normSize;
- // for each node of the face, compute its signed distance to the plane
- vector<double> dist( nbNodes + 1);
- for ( i = 0; i < nbNodes; ++i )
- {
- gp_Vec n2p( xyz[i], point );
- dist[i] = n2p * plnNorm;
- }
- dist.back() = dist.front();
- // find the closest intersection
- int iClosest = -1;
- double rClosest, distClosest = 1e100;;
- gp_Pnt pClosest;
- for ( i = 0; i < nbNodes; ++i )
- {
- double r;
- if ( fabs( dist[i]) < tol )
- r = 0.;
- else if ( fabs( dist[i+1]) < tol )
- r = 1.;
- else if ( dist[i] * dist[i+1] < 0 )
- r = dist[i] / ( dist[i] - dist[i+1] );
- else
- continue; // no intersection
- gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
- gp_Vec p2int ( point, pInt);
- if ( p2int * ray > -tol ) // right half-space
- {
- double intDist = p2int.SquareMagnitude();
- if ( intDist < distClosest )
- {
- iClosest = i;
- rClosest = r;
- pClosest = pInt;
- distClosest = intDist;
- }
- }
- }
- if ( iClosest < 0 )
- return true; // no intesections - out
-
- // analyse transition
- gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
- gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
- gp_Vec p2int ( point, pClosest );
- bool out = (edgeNorm * p2int) < -tol;
- if ( rClosest > 0. && rClosest < 1. ) // not node intersection
- return out;
-
- // ray pass through a face node; analyze transition through an adjacent edge
- gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
- gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
- gp_Vec edgeAdjacent( p1, p2 );
- gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
- bool out2 = (edgeNorm2 * p2int) < -tol;
-
- bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
- return covexCorner ? (out || out2) : (out && out2);
- }
- if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
- {
- // point is out of edge if it is NOT ON any straight part of edge
- // (we consider quadratic edge as being composed of two straight parts)
- for ( i = 1; i < nbNodes; ++i )
- {
- gp_Vec edge( xyz[i-1], xyz[i]);
- gp_Vec n1p ( xyz[i-1], point);
- double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
- if ( dist > tol )
- continue;
- gp_Vec n2p( xyz[i], point );
- if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
- continue;
- return false; // point is ON this part
- }
- return true;
- }
- // Node or 0D element -------------------------------------------------------------------------
- {
- gp_Vec n2p ( xyz[0], point );
- return n2p.Magnitude() <= tol;
- }
- return true;
-}
-
-//=======================================================================
-
-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 );
- }
-
- 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
+ else if (elem->GetType() == SMDSAbs_Volume) // Polyhedral volume
{
- 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) {
+ const SMDS_VtkVolume* aPolyedre = dynamic_cast<const SMDS_VtkVolume*>( elem );
+ if (aPolyedre)
+ {
int nbFaces = aPolyedre->NbFaces();
vector<const SMDS_MeshNode *> poly_nodes;
}
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());
- }
+ {
+ const SMDS_MeshElement* 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());
} // 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;
+ isOk = false;
+ } // switch ( nbNodes )
- for (inode = 1; inode <= nbFaceNodes; inode++) {
- const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
+ } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
- 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
+ if ( isOk ) // the non-poly elem remains valid after sticking nodes
+ {
+ if ( nbNodes != nbUniqueNodes ||
+ !aMesh->ChangeElementNodes( elem, & curNodes[0], nbNodes ))
{
- const SMDSAbs_ElementType etyp = elem->GetType();
- const int elemId = elem->GetID();
- const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
- uniqueNodes.resize(nbUniqueNodes);
+ elemType.Init( elem ).SetID( elem->GetID() );
SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
-
aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
- SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
+
+ uniqueNodes.resize(nbUniqueNodes);
+ SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType );
if ( sm && newElem )
sm->AddElement( newElem );
if ( elem != newElem )
Remove( rmElemIds, false );
Remove( rmNodeIds, true );
+ return;
}
const SMDS_MeshElement* Get() const
{ return myElem; }
- void Set(const SMDS_MeshElement* e) const
- { myElem = e; }
-
-
private:
mutable const SMDS_MeshElement* myElem;
};
//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(set<const SMDS_MeshElement*> & theElements,
- TListOfListOfElementsID & theGroupsOfElementsID)
+
+void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements,
+ TListOfListOfElementsID & theGroupsOfElementsID)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- typedef set<const SMDS_MeshElement*> TElemsSet;
typedef map< SortableElement, int > TMapOfNodeSet;
typedef list<int> TGroupOfElems;
- TElemsSet elems;
if ( theElements.empty() )
{ // get all elements in the mesh
SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
while ( eIt->more() )
- elems.insert( elems.end(), eIt->next());
+ theElements.insert( theElements.end(), eIt->next() );
}
- else
- elems = theElements;
vector< TGroupOfElems > arrayOfGroups;
TGroupOfElems groupOfElems;
TMapOfNodeSet mapOfNodeSet;
- TElemsSet::iterator elemIt = elems.begin();
- for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
+ TIDSortedElemSet::iterator elemIt = theElements.begin();
+ for ( int i = 0; elemIt != theElements.end(); ++elemIt )
+ {
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) ) {
+ if ( !pp.second ) { // one more coincident elem
TMapOfNodeSet::iterator& itSE = pp.first;
- ind = (*itSE).second;
- arrayOfGroups[ind].push_back(curElem->GetID());
+ int ind = (*itSE).second;
+ arrayOfGroups[ind].push_back( curElem->GetID() );
}
else {
- groupOfElems.clear();
- groupOfElems.push_back(curElem->GetID());
- arrayOfGroups.push_back(groupOfElems);
+ arrayOfGroups.push_back( groupOfElems );
+ arrayOfGroups.back().push_back( curElem->GetID() );
i++;
}
}
+ groupOfElems.clear();
vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
- for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
- groupOfElems = *groupIt;
- if ( groupOfElems.size() > 1 ) {
- groupOfElems.sort();
- theGroupsOfElementsID.push_back(groupOfElems);
+ for ( ; groupIt != arrayOfGroups.end(); ++groupIt )
+ {
+ if ( groupIt->size() > 1 ) {
+ //groupOfElems.sort(); -- theElements is sorted already
+ theGroupsOfElementsID.push_back( groupOfElems );
+ theGroupsOfElementsID.back().splice( theGroupsOfElementsID.back().end(), *groupIt );
}
}
}
void SMESH_MeshEditor::MergeEqualElements()
{
- set<const SMDS_MeshElement*> aMeshElements; /* empty input -
- to merge equal elements in the whole mesh */
+ 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 :
TIDSortedElemSet elemSet, avoidSet;
if ( elem )
avoidSet.insert ( elem );
- return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
+ return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
+}
+
+//=======================================================================
+//function : findSegment
+//purpose : Return a mesh segment by two nodes one of which can be medium
+//=======================================================================
+
+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;
}
//=======================================================================
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 );
// find all free border faces sharing form nStart
list< const SMDS_MeshElement* > curElemList;
- list< const SMDS_MeshNode* > nStartList;
+ 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()) {
+ if ( e->IsQuadratic() ) {
const SMDS_VtkFace* F =
dynamic_cast<const SMDS_VtkFace*>(e);
if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
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 )) {
+ if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
cNL->clear();
cFL->clear();
}
//=======================================================================
//function : SewFreeBorder
//purpose :
+//warning : for border-to-side sewing theSideSecondNode is considered as
+// the last side node and theSideThirdNode is not used
//=======================================================================
SMESH_MeshEditor::Sew_Error
// find side nodes and elements
// ====================================
- list< const SMDS_MeshNode* > nSide[ 2 ];
+ list< const SMDS_MeshNode* > nSide[ 2 ];
list< const SMDS_MeshElement* > eSide[ 2 ];
- list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
+ list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
// Free border 1
// 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 ];
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());
GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
}
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
}
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 );
}
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 ( int i = 1; i <= myLastCreatedElems.Length(); ++i )
+ {
+ if ( !myLastCreatedElems(i) ) continue;
+ if ( myLastCreatedElems(i)->GetType() == SMDSAbs_Edge )
+ segments.insert( segments.end(), myLastCreatedElems(i) );
+ else
+ newFaces.Append( 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;
+ 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< int >& group = *itGroups;
+ list< int >::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.Append( *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.Append( 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 ( 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();
}
}
- // edit or replace the face
- SMESHDS_Mesh *aMesh = GetMeshDS();
-
- if (theFace->IsPoly()) {
- aMesh->ChangePolygonNodes(theFace, poly_nodes);
- }
- 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 ];
}
// 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.Append( 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)
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.Append( 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
*/
//=======================================================================
{
nbElem++;
const SMDS_MeshElement* elem = ElemItr->next();
- if( !elem || elem->IsQuadratic() ) continue;
+ 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_BiQuad_Triangle:
+ case SMDSEntity_BiQuad_Quadrangle:
+ case SMDSEntity_TriQuad_Hexa:
+ alreadyOK = theHelper.GetIsBiQuadratic();
+ hasCentralNodes = true;
+ break;
+ default:
+ alreadyOK = true;
+ }
+ // take into account already present modium 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->NbNodes();
- const SMDSAbs_ElementType aType = elem->GetType();
- const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
+ const int 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();
// remove a linear element
GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
+ // remove central nodes of biquadratic elements (biquad->quad convertion)
+ 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 )
break;
default:
NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
- continue;
}
break;
}
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;
continue;
}
ReplaceElemInGroups( elem, NewElem, GetMeshDS());
- if( NewElem )
+ if( NewElem && NewElem->getshapeId() < 1 )
theSm->AddElement( NewElem );
}
return nbElem;
}
-
//=======================================================================
//function : ConvertToQuadratic
//purpose :
//=======================================================================
-void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
+void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
{
SMESHDS_Mesh* meshDS = GetMeshDS();
SMESH_MesherHelper aHelper(*myMesh);
+
aHelper.SetIsQuadratic( true );
+ aHelper.SetIsBiQuadratic( theToBiQuad );
+ aHelper.SetElementsOnShape(true);
+ aHelper.ToFixNodeParameters( true );
+ // convert elements assigned to sub-meshes
int nbCheckedElems = 0;
if ( myMesh->HasShapeToMesh() )
{
}
}
}
+
+ // convert elements NOT assigned to sub-meshes
int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
- if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
+ 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);
+ int 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 || face->IsQuadratic() ) continue;
+ if ( !face ) continue;
+
+ const SMDSAbs_EntityType type = face->GetEntityType();
+ 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 SMDSAbs_EntityType type = face->GetEntityType();
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 int id = volume->GetID();
const SMDSAbs_EntityType type = volume->GetEntityType();
+ if ( volume->IsQuadratic() )
+ {
+ bool alreadyOK;
+ switch ( type )
+ {
+ case SMDSEntity_Quad_Hexa: alreadyOK = !theToBiQuad; break;
+ case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
+ default: alreadyOK = true;
+ }
+ if ( alreadyOK )
+ {
+ aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
+ continue;
+ }
+ }
+ const int 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();
NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
break;
case SMDSEntity_Hexa:
+ case SMDSEntity_Quad_Hexa:
+ 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],
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();
+ // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+ // aHelper.FixQuadraticElements(myError);
+ SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
}
}
/*!
* \brief Makes given elements quadratic
* \param theForce3d - if true, the medium nodes will be placed in the middle of link
- * \param theElements - elements to make quadratic
+ * \param theElements - elements to make quadratic
*/
//================================================================================
void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
- TIDSortedElemSet& theElements)
+ TIDSortedElemSet& theElements,
+ const bool theToBiQuad)
{
if ( theElements.empty() ) return;
// we believe that all theElements are of the same type
const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
-
+
// get all nodes shared by theElements
TIDSortedNodeSet allNodes;
TIDSortedElemSet::iterator eIt = theElements.begin();
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[ e->GetType() ].insert( e );
- continue;
- }
- if ( e->GetType() >= elemType )
- {
- continue; // same type of more complex linear element
+ 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 )
+ continue;
}
+ 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 );
}
SMESH_MesherHelper helper(*myMesh);
helper.SetIsQuadratic( true );
+ helper.SetIsBiQuadratic( theToBiQuad );
// add links of quadratic adjacent elements to the helper
helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
}
- // make quadratic elements instead of linear ones
+ // make quadratic (or bi-tri-quadratic) elements instead of linear ones
- SMESHDS_Mesh* meshDS = GetMeshDS();
+ SMESHDS_Mesh* meshDS = GetMeshDS();
SMESHDS_SubMesh* smDS = 0;
for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
{
const SMDS_MeshElement* elem = *eIt;
- if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
- continue;
- const int id = elem->GetID();
+ 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 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);
SMDS_MeshElement * newElem = 0;
- switch( nodes.size() )
+ switch( nbNodes )
{
case 4: // cases for most frequently used element types go first (for optimization)
if ( type == SMDSAbs_Volume )
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();
+ // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+ // helper.FixQuadraticElements( myError );
+ SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
}
}
{
int 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 );
}
// 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 = elemSetIterator( theElements );
removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
// we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
const SMDS_MeshElement* eComplex = invIt2->next();
if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
{
- int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
+ int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e, eComplex ).size();
if ( nbCommonNodes == e->NbNodes())
{
complexFound = true;
}
}
}
- elemIt = SMDS_ElemIteratorPtr
- (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
+ elemIt = elemSetIterator( moreElemsToConvert );
removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
}
//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;
if ( aResult != SEW_OK)
return aResult;
- list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
+ list< int > 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 ) {
+ if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second )
+ {
const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
nodeIDsToRemove.push_back( nToRemove->GetID() );
// loop on elements sharing nToRemove
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 );
+ nodes.resize( nbNodes );
SMDS_ElemIteratorPtr nIt = e->nodesIterator();
while ( nIt->more() ) {
- const SMDS_MeshNode* n =
- static_cast<const SMDS_MeshNode*>( nIt->next() );
+ const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nIt->next() );
nnIt = nReplaceMap.find( n );
if ( nnIt != nReplaceMap.end() ) {
nbReplaced++;
// elemIDsToRemove.push_back( e->GetID() );
// else
if ( nbReplaced )
+ {
+ elemType.Init( e, /*basicOnly=*/false ).SetID( e->GetID() );
+ aMesh->RemoveElement( e );
+
+ if ( SMDS_MeshElement* newElem = this->AddElement( nodes, elemType ))
{
- 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);
+ AddToSameGroups( newElem, e, aMesh );
+ if ( int aShapeId = e->getshapeId() )
+ aMesh->SetMeshElementOnShape( newElem, aShapeId );
}
+ }
}
}
return SEW_OK;
}
+//================================================================================
+/*!
+ * \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;
+ SMDS_ElemIteratorPtr elemIt;
+ vector< const SMDS_MeshElement* > allElems;
+ 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] ))
+ {
+ type = types[i];
+ break;
+ }
+ // put all elements in the vector <allElems>
+ allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
+ elemIt = mesh->elementsIterator( type );
+ while ( elemIt->more() )
+ allElems.push_back( elemIt->next());
+ elemIt = elemSetIterator( allElems );
+ }
+ else
+ {
+ type = (*theElements.begin())->GetType();
+ elemIt = elemSetIterator( theElements );
+ }
+
+ // duplicate elements
+
+ ElemFeatures elemType;
+
+ vector< const SMDS_MeshNode* > nodes;
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* elem = elemIt->next();
+ if ( elem->GetType() != type )
+ continue;
+
+ elemType.Init( elem, /*basicOnly=*/false );
+ nodes.assign( elem->begin_nodes(), elem->end_nodes() );
+
+ AddElement( nodes, elemType );
+ }
+}
+
//================================================================================
/*!
\brief Creates a hole in a mesh by doubling the nodes of some particular elements
\param theElems - the list of elements (edges or faces) to be replicated
The nodes for duplication could be found from these elements
\param theNodesNot - list of nodes to NOT replicate
- \param theAffectedElems - the list of elements (cells and edges) to which the
+ \param theAffectedElems - the list of elements (cells and edges) to which the
replicated nodes should be associated to.
\return TRUE if operation has been completed successfully, FALSE otherwise
*/
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 )
{
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() )
+ while ( anIter->more() )
+ {
+ 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 );
}
continue;
if ( theIsDoubleElem )
- AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
+ AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false ));
else
+ 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
+ \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+//================================================================================
+
+bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
+ const std::list< int >& theListOfModifiedElems )
+{
+ MESSAGE("DoubleNodes");
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ if ( theListOfNodes.size() == 0 )
+ return false;
+
+ SMESHDS_Mesh* aMeshDS = GetMeshDS();
+ if ( !aMeshDS )
+ return false;
+
+ // iterate through nodes and duplicate them
+
+ std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+
+ std::list< int >::const_iterator aNodeIter;
+ for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
+ {
+ int aCurr = *aNodeIter;
+ SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
+ if ( !aNode )
+ continue;
+
+ // duplicate node
+
+ const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
+ if ( aNewNode )
+ {
+ 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;
+ }
+ anElemToNodes[ anElem ] = aNodeArr;
+ }
+
+ // Change nodes of elements
+
+ std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
+ anElemToNodesIter = anElemToNodes.begin();
+ for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
+ {
+ const SMDS_MeshElement* anElem = anElemToNodesIter->first;
+ vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
+ if ( anElem )
+ {
+ MESSAGE("ChangeElementNodes");
+ aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
+ }
+ }
+
+ return true;
+}
+
+namespace {
+
+ //================================================================================
+ /*!
+ \brief Check if element located inside shape
+ \return TRUE if IN or ON shape, FALSE otherwise
+ */
+ //================================================================================
+
+ template<class Classifier>
+ bool isInside(const SMDS_MeshElement* theElem,
+ Classifier& theClassifier,
+ const double theTol)
+ {
+ gp_XYZ centerXYZ (0, 0, 0);
+ SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
+ while (aNodeItr->more())
+ centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
+
+ gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
+ theClassifier.Perform(aPnt, theTol);
+ TopAbs_State aState = theClassifier.State();
+ return (aState == TopAbs_IN || aState == TopAbs_ON );
+ }
+
+ //================================================================================
+ /*!
+ * \brief Classifier of the 3D point on the TopoDS_Face
+ * with interaface suitable for isInside()
+ */
+ //================================================================================
+
+ struct _FaceClassifier
+ {
+ Extrema_ExtPS _extremum;
+ BRepAdaptor_Surface _surface;
+ TopAbs_State _state;
+
+ _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
+ {
+ _extremum.Initialize( _surface,
+ _surface.FirstUParameter(), _surface.LastUParameter(),
+ _surface.FirstVParameter(), _surface.LastVParameter(),
+ _surface.Tolerance(), _surface.Tolerance() );
+ }
+ void Perform(const gp_Pnt& aPnt, double theTol)
+ {
+ theTol *= theTol;
+ _state = TopAbs_OUT;
+ _extremum.Perform(aPnt);
+ if ( _extremum.IsDone() )
+ for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
+ _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
+ }
+ TopAbs_State State() const
+ {
+ return _state;
+ }
+ };
+}
+
+//================================================================================
+/*!
+ \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 theShape - shape to detect affected elements (element which geometric center
+ 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
+ \sa DoubleNodeElemGroupsInRegion()
+ */
+//================================================================================
+
+bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
+ const TIDSortedElemSet& theNodesNot,
+ const TopoDS_Shape& theShape,
+ TIDSortedElemSet& theAffectedElems)
+{
+ if ( theShape.IsNull() )
+ {
+ std::set<const SMDS_MeshNode*> alreadyCheckedNodes;
+ std::set<const SMDS_MeshElement*> alreadyCheckedElems;
+ std::set<const SMDS_MeshElement*> edgesToCheck;
+ alreadyCheckedNodes.clear();
+ alreadyCheckedElems.clear();
+ edgesToCheck.clear();
+
+ // --- iterates on elements to be replicated and get elements by back references from their nodes
+
+ TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+ int ielem;
+ for ( ielem=1; elemItr != theElems.end(); ++elemItr )
+ {
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+ if (!anElem || (anElem->GetType() != SMDSAbs_Face))
+ continue;
+ gp_XYZ normal;
+ SMESH_MeshAlgos::FaceNormal( anElem, normal, /*normalized=*/true );
+ MESSAGE("element " << ielem++ << " normal " << normal.X() << " " << normal.Y() << " " << normal.Z());
+ std::set<const SMDS_MeshNode*> nodesElem;
+ nodesElem.clear();
+ SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+ while ( nodeItr->more() )
+ {
+ const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+ nodesElem.insert(aNode);
+ }
+ std::set<const SMDS_MeshNode*>::iterator nodit = nodesElem.begin();
+ for (; nodit != nodesElem.end(); nodit++)
+ {
+ MESSAGE(" noeud ");
+ const SMDS_MeshNode* aNode = *nodit;
+ if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+ continue;
+ if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end())
+ continue;
+ alreadyCheckedNodes.insert(aNode);
+ SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+ while ( backElemItr->more() )
+ {
+ MESSAGE(" backelem ");
+ const SMDS_MeshElement* curElem = backElemItr->next();
+ if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end())
+ continue;
+ if (theElems.find(curElem) != theElems.end())
+ continue;
+ alreadyCheckedElems.insert(curElem);
+ double x=0, y=0, z=0;
+ int nb = 0;
+ SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator();
+ while ( nodeItr2->more() )
+ {
+ const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next());
+ x += anotherNode->X();
+ y += anotherNode->Y();
+ z += anotherNode->Z();
+ nb++;
+ }
+ gp_XYZ p;
+ p.SetCoord( x/nb -aNode->X(),
+ y/nb -aNode->Y(),
+ z/nb -aNode->Z() );
+ MESSAGE(" check " << p.X() << " " << p.Y() << " " << p.Z());
+ if (normal*p > 0)
+ {
+ MESSAGE(" --- inserted")
+ theAffectedElems.insert( curElem );
+ }
+ else if (curElem->GetType() == SMDSAbs_Edge)
+ edgesToCheck.insert(curElem);
+ }
+ }
+ }
+ // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes)
+ std::set<const SMDS_MeshElement*>::iterator eit = edgesToCheck.begin();
+ for( ; eit != edgesToCheck.end(); eit++)
+ {
+ bool onside = true;
+ const SMDS_MeshElement* anEdge = *eit;
+ SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator();
+ while ( nodeItr->more() )
+ {
+ const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+ if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end())
+ {
+ onside = false;
+ break;
+ }
+ }
+ if (onside)
+ {
+ MESSAGE(" --- edge onside inserted")
+ theAffectedElems.insert(anEdge);
+ }
+ }
+ }
+ else
+ {
+ const double aTol = Precision::Confusion();
+ auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
+ auto_ptr<_FaceClassifier> aFaceClassifier;
+ if ( theShape.ShapeType() == TopAbs_SOLID )
+ {
+ bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
+ bsc3d->PerformInfinitePoint(aTol);
+ }
+ else if (theShape.ShapeType() == TopAbs_FACE )
+ {
+ aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
+ }
+
+ // iterates on indicated elements and get elements by back references from their nodes
+ TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+ int ielem;
+ for ( ielem = 1; elemItr != theElems.end(); ++elemItr )
+ {
+ MESSAGE("element " << ielem++);
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+ if (!anElem)
+ continue;
+ SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+ while ( nodeItr->more() )
+ {
+ MESSAGE(" noeud ");
+ const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+ if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+ continue;
+ SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+ while ( backElemItr->more() )
+ {
+ MESSAGE(" backelem ");
+ 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 true;
+}
+
+//================================================================================
+/*!
+ \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+ \param theElems - group of of elements (edges or faces) to be replicated
+ \param theNodesNot - group of nodes not to replicate
+ \param theShape - shape to detect affected elements (element which geometric center
+ located on or inside shape).
+ The replicated nodes should be associated to affected elements.
+ \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+//================================================================================
+
+bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
+ const TIDSortedElemSet& theNodesNot,
+ const TopoDS_Shape& theShape )
+{
+ if ( theShape.IsNull() )
+ return false;
+
+ const double aTol = Precision::Confusion();
+ SMESHUtils::Deleter< BRepClass3d_SolidClassifier> bsc3d;
+ SMESHUtils::Deleter<_FaceClassifier> aFaceClassifier;
+ if ( theShape.ShapeType() == TopAbs_SOLID )
+ {
+ bsc3d._obj = new BRepClass3d_SolidClassifier( theShape );
+ bsc3d->PerformInfinitePoint(aTol);
+ }
+ else if (theShape.ShapeType() == TopAbs_FACE )
+ {
+ aFaceClassifier._obj = new _FaceClassifier( TopoDS::Face( theShape ));
+ }
+
+ // iterates on indicated elements and get elements by back references from their nodes
+ TIDSortedElemSet anAffected;
+ TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+ for ( ; elemItr != theElems.end(); ++elemItr )
+ {
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+ if (!anElem)
+ continue;
+
+ SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+ while ( nodeItr->more() )
+ {
+ const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+ if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+ continue;
+ SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+ while ( backElemItr->more() )
{
- MESSAGE("ChangeElementNodes");
- theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
+ const SMDS_MeshElement* curElem = backElemItr->next();
+ if ( curElem && theElems.find(curElem) == theElems.end() &&
+ ( bsc3d ?
+ isInside( curElem, *bsc3d, aTol ) :
+ isInside( curElem, *aFaceClassifier, aTol )))
+ anAffected.insert( curElem );
}
- res = true;
+ }
}
- return res;
+ return DoubleNodes( theElems, theNodesNot, anAffected );
}
-//================================================================================
/*!
- \brief Creates a hole in a mesh by doubling the nodes of some particular elements
- \param theNodes - identifiers of nodes to be doubled
- \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
- nodes. If list of element identifiers is empty then nodes are doubled but
- they not assigned to elements
- \return TRUE if operation has been completed successfully, FALSE otherwise
-*/
-//================================================================================
+ * \brief compute an oriented angle between two planes defined by four points.
+ * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
+ * @param p0 base of the rotation axe
+ * @param p1 extremity of the rotation axe
+ * @param g1 belongs to the first plane
+ * @param g2 belongs to the second plane
+ */
+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);
+ try {
+ return n2.AngleWithRef(n1, vref);
+ }
+ catch ( Standard_Failure ) {
+ }
+ return Max( v1.Magnitude(), v2.Magnitude() );
+}
-bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
- const std::list< int >& theListOfModifiedElems )
+/*!
+ * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
+ * The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
+ * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
+ * Triangles are transformed into prisms, and quadrangles into hexahedrons.
+ * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
+ * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list.
+ * 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
+ * \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 onAllBoundaries)
{
- MESSAGE("DoubleNodes");
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ MESSAGE("----------------------------------------------");
+ MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
+ MESSAGE("----------------------------------------------");
- if ( theListOfNodes.size() == 0 )
- return false;
+ SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
+ meshDS->BuildDownWardConnectivity(true);
+ CHRONO(50);
+ SMDS_UnstructuredGrid *grid = meshDS->getGrid();
- SMESHDS_Mesh* aMeshDS = GetMeshDS();
- if ( !aMeshDS )
- return false;
+ // --- 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
+ // build the list of nodes shared by 2 or more domains, with their domain indexes
- // iterate through nodes and duplicate them
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
+ std::map<int,int>celldom; // cell vtkId --> domain
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
+ std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
+ faceDomains.clear();
+ celldom.clear();
+ cellDomains.clear();
+ nodeDomains.clear();
+ std::map<int,int> emptyMap;
+ std::set<int> emptySet;
+ emptyMap.clear();
- std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+ MESSAGE(".. Number of domains :"<<theElems.size());
- std::list< int >::const_iterator aNodeIter;
- for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
+ 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 < nbDomains-1; idom++)
{
- int aCurr = *aNodeIter;
- SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
- if ( !aNode )
- continue;
+ // 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 ))
+ {
+ MESSAGE(".... Domain #" << idom);
+ MESSAGE(".... Domain #" << idombis);
+ throw SALOME_Exception("The domains are not disjoint.");
+ return false ;
+ }
+ }
+ }
+ }
- // duplicate node
+ for (int idom = 0; idom < nbDomains; idom++)
+ {
- const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
- if ( aNewNode )
+ // --- 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)
{
- anOldNodeToNewNode[ aNode ] = aNewNode;
- myLastCreatedNodes.Append( aNewNode );
+ const SMDS_MeshElement* anElem = *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++)
+ {
+ int 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
+ {
+ 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))
+ {
+ 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;
+ }
+ }
+ }
+ }
}
}
- // Create map of new nodes for modified elements
+ //MESSAGE("Number of shared faces " << faceDomains.size());
+ std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
- std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
+ // --- explore the shared faces domain by domain,
+ // 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)
- std::list< int >::const_iterator anElemIter;
- for ( anElemIter = theListOfModifiedElems.begin();
- anElemIter != theListOfModifiedElems.end(); ++anElemIter )
+ for (int idomain = idom0; idomain < nbDomains; idomain++)
{
- int aCurr = *anElemIter;
- SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
- if ( !anElem )
- continue;
+ //MESSAGE("Domain " << idomain);
+ const TIDSortedElemSet& domain = (idomain == iRestDom) ? theRestDomElems : 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 = 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);
+ cellDomains[aCell][idomain] = vtkId;
+ celldom[vtkId] = idomain;
+ //MESSAGE(" cell " << vtkId << " domain " << idomain);
+ }
+ }
+ }
+ }
- vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
+ // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
+ // for each shared face, get the nodes
+ // for each node, for each domain of the face, create a clone of the node
- 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() )
+ // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
+ // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
+ // the value is the ordered domain ids. (more than 4 domains not taken into account)
+
+ std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
+ 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 = idom0; idomain < nbDomains; 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)
{
- const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
- aNodeArr[ ind++ ] = aNewNode;
+ int oldId = *itn;
+ 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>::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
+ {
+ 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());
+ }
+ }
}
- else
- aNodeArr[ ind++ ] = aCurrNode;
}
- anElemToNodes[ anElem ] = aNodeArr;
}
- // Change nodes of elements
-
- std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
- anElemToNodesIter = anElemToNodes.begin();
- for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
+ MESSAGE(".. Creation of elements");
+ for (int idomain = idom0; idomain < nbDomains; idomain++)
{
- const SMDS_MeshElement* anElem = anElemToNodesIter->first;
- vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
- if ( anElem )
+ 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)
{
- MESSAGE("ChangeElementNodes");
- aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
+ 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)
+ {
+ 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 ]))
+ {
+ 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_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 ( size_t id = 0; id < doms.size(); id++ )
+ {
+ int idom = doms[id];
+ const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom];
+ for ( int ivol = 0; ivol < nbvol; ivol++ )
+ {
+ int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
+ SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
+ if (domain.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
+ }
+ }
+ }
+ }
}
+ }
}
- return true;
-}
+ // --- iterate on shared faces (volumes to modify, face to extrude)
+ // get node id's of the face (id SMDS = id VTK)
+ // create flat element with old and new nodes if requested
-namespace {
+ // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
+ // (domain1 X domain2) = domain1 + MAXINT*domain2
- //================================================================================
- /*!
- \brief Check if element located inside shape
- \return TRUE if IN or ON shape, FALSE otherwise
- */
- //================================================================================
+ std::map<int, std::map<long,int> > nodeQuadDomains;
+ std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
- template<class Classifier>
- bool isInside(const SMDS_MeshElement* theElem,
- Classifier& theClassifier,
- const double theTol)
+ MESSAGE(".. Creation of elements: simple junction");
+ if (createJointElems)
{
- gp_XYZ centerXYZ (0, 0, 0);
- SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
- while (aNodeItr->more())
- centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
-
- gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
- theClassifier.Perform(aPnt, theTol);
- TopAbs_State aState = theClassifier.State();
- return (aState == TopAbs_IN || aState == TopAbs_ON );
+ 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());
+ }
}
- //================================================================================
- /*!
- * \brief Classifier of the 3D point on the TopoDS_Face
- * with interaface suitable for isInside()
- */
- //================================================================================
+ // --- create volumes on multiple domain intersection if requested
+ // iterate on mutipleNodesToFace
+ // iterate on edgesMultiDomains
- struct _FaceClassifier
+ MESSAGE(".. Creation of elements: multiple junction");
+ if (createJointElems)
{
- Extrema_ExtPS _extremum;
- BRepAdaptor_Surface _surface;
- TopAbs_State _state;
+ // --- iterate on mutipleNodesToFace
- _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
- {
- _extremum.Initialize( _surface,
- _surface.FirstUParameter(), _surface.LastUParameter(),
- _surface.FirstVParameter(), _surface.LastVParameter(),
- _surface.Tolerance(), _surface.Tolerance() );
- }
- void Perform(const gp_Pnt& aPnt, double theTol)
+ std::map<int, std::vector<int> >::iterator itn = mutipleNodesToFace.begin();
+ for (; itn != mutipleNodesToFace.end(); ++itn)
{
- _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
+ 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;
+ 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)
{
- return _state;
+ 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
+ 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());
+ }
+ else
+ {
+ //INFOS("Quadratic multiple joints not implemented");
+ // TODO quadratic nodes
+ }
}
- };
-}
+ }
-//================================================================================
-/*!
- \brief Creates a hole in a mesh by doubling the nodes of some particular elements
- \param theElems - group of of elements (edges or faces) to be replicated
- \param theNodesNot - group of nodes not to replicate
- \param theShape - shape to detect affected elements (element which geometric center
- located on or inside shape).
- The replicated nodes should be associated to affected elements.
- \return TRUE if operation has been completed successfully, FALSE otherwise
-*/
-//================================================================================
+ // --- 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.
+ // associate these faces or edges to their corresponding domain.
+ // only the first domain found is kept when a face or edge is shared
-bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
- const TIDSortedElemSet& theNodesNot,
- const TopoDS_Shape& theShape )
-{
- if ( theShape.IsNull() )
- return false;
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
+ std::map<int,int> feDom; // vtk id of cell to modify --> id domain
+ faceOrEdgeDom.clear();
+ feDom.clear();
- 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 )
+ MESSAGE(".. Modification of elements");
+ for (int idomain = idom0; idomain < nbDomains; idomain++)
{
- aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
+ 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 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);
+ }
+ }
+ }
}
- // iterates on indicated elements and get elements by back references from their nodes
- TIDSortedElemSet anAffected;
- TIDSortedElemSet::const_iterator elemItr = theElems.begin();
- for ( ; elemItr != theElems.end(); ++elemItr )
- {
- SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
- if (!anElem)
- continue;
+ // --- iterate on shared faces (volumes to modify, face to extrude)
+ // get node id's of the face
+ // replace old nodes by new nodes in volumes, and update inverse connectivity
- SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
- while ( nodeItr->more() )
+ 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)
{
- const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
- if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
- continue;
- SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
- while ( backElemItr->more() )
+ 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)
{
- const SMDS_MeshElement* curElem = backElemItr->next();
- if ( curElem && theElems.find(curElem) == theElems.end() &&
- ( bsc3d.get() ?
- isInside( curElem, *bsc3d, aTol ) :
- isInside( curElem, *aFaceClassifier, aTol )))
- anAffected.insert( curElem );
+ 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);
}
}
}
- return DoubleNodes( theElems, theNodesNot, anAffected );
-}
-/*!
- * \brief compute an oriented angle between two planes defined by four points.
- * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
- * @param p0 base of the rotation axe
- * @param p1 extremity of the rotation axe
- * @param g1 belongs to the first plane
- * @param g2 belongs to the second plane
- */
-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);
+ // 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();
+
+ CHRONOSTOP(50);
+ counters::stats();
+ return true;
}
/*!
- * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
- * The list of groups must describe a partition of the mesh volumes.
- * The nodes of the internal faces at the boundaries of the groups are doubled.
- * In option, the internal faces are replaced by flat elements.
+ * \brief Double nodes on some external faces and create flat elements.
+ * Flat elements are mainly used by some types of mechanic calculations.
+ *
+ * Each group of the list must be constituted of faces.
* Triangles are transformed in prisms, and quadrangles in hexahedrons.
- * The flat elements are stored in groups of volumes.
- * @param theElems - list of groups of volumes, where a group of volume is a set of
+ * @param theElems - list of groups of faces, where a group of faces is a set of
* SMDS_MeshElements sorted by Id.
- * @param createJointElems - if TRUE, create the elements
* @return TRUE if operation has been completed successfully, FALSE otherwise
*/
-bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
- bool createJointElems)
+bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
{
- MESSAGE("----------------------------------------------");
- MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
- MESSAGE("----------------------------------------------");
+ MESSAGE("-------------------------------------------------");
+ MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
+ MESSAGE("-------------------------------------------------");
SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
- meshDS->BuildDownWardConnectivity(true);
- CHRONO(50);
- SMDS_UnstructuredGrid *grid = meshDS->getGrid();
- // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
- // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
- // build the list of nodes shared by 2 or more domains, with their domain indexes
+ // --- For each group of faces
+ // duplicate the nodes, create a flat element based on the face
+ // replace the nodes of the faces by their clones
- std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
- std::map<int,int>celldom; // cell vtkId --> domain
- std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
- std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
- faceDomains.clear();
- celldom.clear();
- cellDomains.clear();
- nodeDomains.clear();
- std::map<int,int> emptyMap;
- std::set<int> emptySet;
- emptyMap.clear();
+ std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
+ std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
+ clonedNodes.clear();
+ intermediateNodes.clear();
+ 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 )
{
+ 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
- // --- build a map (face to duplicate --> volume to modify)
- // with all the faces shared by 2 domains (group of elements)
- // and corresponding volume of this domain, for each shared face.
- // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
+ 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);
- //MESSAGE("Domain " << idom);
- const TIDSortedElemSet& domain = theElems[idom];
- TIDSortedElemSet::const_iterator elemItr = domain.begin();
- for (; elemItr != domain.end(); ++elemItr)
+ const SMDS_MeshNode* clone = 0;
+ if (!clonedNodes.count(node))
{
- 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++)
- {
- int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
- const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
- if (! domain.count(elem)) // neighbor is in another domain : face is shared
- {
- DownIdType face(downIds[n], downTypes[n]);
- if (!faceDomains.count(face))
- faceDomains[face] = emptyMap; // create an empty entry for face
- if (!faceDomains[face].count(idom))
- {
- faceDomains[face][idom] = vtkId; // volume associated to face in this domain
- celldom[vtkId] = idom;
- //MESSAGE(" cell with a border " << vtkId << " domain " << idom);
- }
- }
- }
+ clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
+ copyPosition( node, clone );
+ clonedNodes[node] = clone;
}
- }
-
- //MESSAGE("Number of shared faces " << faceDomains.size());
- std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
+ else
+ clone = clonedNodes[node];
- // --- explore the shared faces domain by domain,
- // 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)
+ if (isMedium)
+ ln3.push_back(clone);
+ else
+ ln1.push_back(clone);
- for (int idomain = 0; idomain < theElems.size(); idomain++)
- {
- //MESSAGE("Domain " << idomain);
- const TIDSortedElemSet& domain = theElems[idomain];
- itface = faceDomains.begin();
- for (; itface != faceDomains.end(); ++itface)
+ const SMDS_MeshNode* inter = 0;
+ if (isQuad && (!isMedium))
{
- 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);
- std::set<int> cells;
- cells.clear();
- 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 (celldom.count(vtkId))
- continue;
- cellDomains[aCell][idomain] = vtkId;
- celldom[vtkId] = idomain;
- //MESSAGE(" cell " << vtkId << " domain " << idomain);
- }
- }
+ if (!intermediateNodes.count(node))
+ {
+ inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
+ copyPosition( node, inter );
+ intermediateNodes[node] = inter;
+ }
+ else
+ inter = intermediateNodes[node];
+ ln4.push_back(inter);
}
+ }
+
+ // --- 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;
+ 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());
+ }
+
+ // --- modify the face
+
+ aFace->ChangeNodes(&ln[0], ln.size());
}
+ }
+ return true;
+}
- // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
- // for each shared face, get the nodes
- // for each node, for each domain of the face, create a clone of the node
+/*!
+ * \brief identify all the elements around a geom shape, get the faces delimiting the hole
+ * Build groups of volume to remove, groups of faces to replace on the skin of the object,
+ * 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,
+ std::vector<std::vector<int> >& listOfListOfNodes)
+{
+ 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,
+ // 2 either by a group of nodes (representative of the shape)to use with the radius,
+ // 3 either by a group of nodes where all the elements build on one of this nodes are to remove,
+ // In the case 2, the group of nodes is an external group of nodes from another mesh,
+ // In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
+ // defined by it's name.
+
+ 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;
+ }
+
+ 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 (nodesCoords.size() > 0)
+ isNodeCoords = true; // a list o nodes given by their coordinates
+ //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
+
+ // --- define groups to build
+
+ int idg; // --- group of SMDS volumes
+ string grpvName = groupName;
+ grpvName += "_vol";
+ SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
+ if (!grp)
+ {
+ MESSAGE("group not created " << grpvName);
+ return;
+ }
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
+
+ int idgs; // --- group of SMDS faces on the skin
+ string grpsName = groupName;
+ grpsName += "_skin";
+ SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
+ if (!grps)
+ {
+ MESSAGE("group not created " << grpsName);
+ return;
+ }
+ SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
+
+ int idgi; // --- group of SMDS faces internal (several shapes)
+ string grpiName = groupName;
+ grpiName += "_internalFaces";
+ SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
+ if (!grpi)
+ {
+ MESSAGE("group not created " << grpiName);
+ return;
+ }
+ SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
+
+ int idgei; // --- group of SMDS faces internal (several shapes)
+ string grpeiName = groupName;
+ grpeiName += "_internalEdges";
+ SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
+ if (!grpei)
+ {
+ 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();
+
+ // --- set of volumes detected inside
+
+ std::set<int> setOfInsideVol;
+ std::set<int> setOfVolToCheck;
- // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
- // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
- // the value is the ordered domain ids. (more than 4 domains not taken into account)
+ std::vector<gp_Pnt> gpnts;
+ gpnts.clear();
- std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
- 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)
+ 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() )
+ {
+ 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 )
+ {
+ 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;
- for (int idomain = 0; idomain < theElems.size(); idomain++)
+ for ( int i = 1; i <= vertexMap.Extent(); ++i )
{
- 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);
- bool isMultipleDetected = false;
- std::set<int>::iterator itn = oldNodes.begin();
- for (; itn != oldNodes.end(); ++itn)
- {
- int oldId = *itn;
- //MESSAGE(" 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
- 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);
- isMultipleDetected =true;
- 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(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
- }
- if (nodeDomains[oldId].size() >= 3)
- {
- //MESSAGE("confirm multiple node " << oldId);
- isMultipleDetected =true;
- }
- }
- }
- if (isMultipleDetected) // 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)
- {
- 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]))
- {
- vector<int> vn0 = mutipleNodes[nodes[0]];
- vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
- sort( vn0.begin(), vn0.end() );
- sort( vn1.begin(), vn1.end() );
- if (vn0 == vn1)
- {
- //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 < vn0.size(); id++)
- {
- int idom = vn0[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 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());
}
+ }
- // --- iterate on shared faces (volumes to modify, face to extrude)
- // get node id's of the face (id SMDS = id VTK)
- // create flat element with old and new nodes if requested
+ if (gpnts.size() > 0)
+ {
+ int nodeId = 0;
+ const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
+ if (startNode)
+ nodeId = startNode->GetID();
+ MESSAGE("nodeId " << nodeId);
- // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
- // (domain1 X domain2) = domain1 + MAXINT*domain2
+ double radius2 = radius*radius;
+ MESSAGE("radius2 " << radius2);
- std::map<int, std::map<long,int> > nodeQuadDomains;
- std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
+ // --- volumes on start node
- if (createJointElems)
+ setOfVolToCheck.clear();
+ SMDS_MeshElement* startVol = 0;
+ SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
+ while (volItr->more())
{
- 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;
- int idg;
- 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());
- }
+ startVol = (SMDS_MeshElement*)volItr->next();
+ setOfVolToCheck.insert(startVol->getVtkId());
+ }
+ if (setOfVolToCheck.empty())
+ {
+ MESSAGE("No volumes found");
+ return;
}
- // --- create volumes on multiple domain intersection if requested
- // iterate on mutipleNodesToFace
- // iterate on edgesMultiDomains
+ // --- 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
- if (createJointElems)
+ std::map<int, double> mapOfNodeDistance2;
+ mapOfNodeDistance2.clear();
+ std::set<int> setOfOutsideVol;
+ while (!setOfVolToCheck.empty())
{
- // --- iterate on mutipleNodesToFace
-
- std::map<int, std::vector<int> >::iterator itn = mutipleNodesToFace.begin();
- for (; itn != mutipleNodesToFace.end(); ++itn)
+ 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 distance2 = 0;
+ if (mapOfNodeDistance2.count(pts[i]))
{
- 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)
+ distance2 = mapOfNodeDistance2[pts[i]];
+ MESSAGE("point " << pts[i] << " distance2 " << distance2);
+ }
+ else
{
- 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);
-
- stringstream grpname;
- grpname << "mj_";
- grpname << 0 << "_" << 0;
- 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());
- }
- else
+ 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)
{
- MESSAGE("Quadratic multiple joints not implemented");
- // TODO quadratic nodes
+ distance2 = d2;
+ if (distance2 < radius2)
+ break;
}
+ }
+ 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);
}
+ }
- // --- 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.
- // associate these faces or edges to their corresponding domain.
- // only the first domain found is kept when a face or edge is shared
-
- std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
- std::map<int,int> feDom; // vtk id of cell to modify --> id domain
- faceOrEdgeDom.clear();
- feDom.clear();
+ // --- for outside hexahedrons, check if they have more than one neighbor volume inside
+ // If yes, add the volume to the inside set
- for (int idomain = 0; idomain < theElems.size(); idomain++)
+ 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)
{
- std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
- for (; itnod != nodeDomains.end(); ++itnod)
+ 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)
{
- int oldId = itnod->first;
- //MESSAGE(" node " << oldId);
- vtkCellLinks::Link l = 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))
- {
- 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);
- }
- }
+ 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);
}
+ }
- // --- iterate on shared faces (volumes to modify, face to extrude)
- // get node id's of the face
- // replace old nodes by new nodes in volumes, and update inverse connectivity
+ // --- 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)
+ // fill group of SMDS faces inside the volume (when several volume shapes)
+ // fill group of SMDS faces on the skin of the global volume (if skin)
- std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
- for (int m=0; m<3; m++)
+ std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
+ 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++)
{
- std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
- itface = (*amap).begin();
- for (; itface != (*amap).end(); ++itface)
+ 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 = 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);
- }
+ 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));
+ }
}
+ }
- meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
- grid->BuildLinks();
+ // --- identify the edges constituting the wire of each subshape on the skin
+ // define polylines with the nodes of edges, equivalent to wires
+ // project polylines on subshapes, and partition, to get geom faces
- CHRONOSTOP(50);
- counters::stats();
- return true;
-}
+ std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
+ std::set<int> emptySet;
+ emptySet.clear();
+ std::set<int> shapeIds;
-/*!
- * \brief Double nodes on some external faces and create flat elements.
- * Flat elements are mainly used by some types of mechanic calculations.
- *
- * Each group of the list must be constituted of faces.
- * Triangles are transformed in prisms, and quadrangles in hexahedrons.
- * @param theElems - list of groups of faces, where a group of faces is a set of
- * SMDS_MeshElements sorted by Id.
- * @return TRUE if operation has been completed successfully, FALSE otherwise
- */
-bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
-{
- MESSAGE("-------------------------------------------------");
- MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
- MESSAGE("-------------------------------------------------");
+ 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))
+ {
+ shapeIdToVtkIdSet[shapeId] = emptySet;
+ shapeIds.insert(shapeId);
+ }
+ shapeIdToVtkIdSet[shapeId].insert(vtkId);
+ }
- SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
+ std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
+ std::set<DownIdType, DownIdCompare> emptyEdges;
+ emptyEdges.clear();
- // --- For each group of faces
- // duplicate the nodes, create a flat element based on the face
- // replace the nodes of the faces by their clones
+ 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;
- std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
- std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
- clonedNodes.clear();
- intermediateNodes.clear();
- std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
- mapOfJunctionGroups.clear();
+ std::vector<int> nodesEdges;
- for (int idom = 0; idom < theElems.size(); idom++)
+ std::set<int>::iterator its = itShape->second.begin();
+ for (; its != itShape->second.end(); ++its)
{
- const TIDSortedElemSet& domain = theElems[idom];
- TIDSortedElemSet::const_iterator elemItr = domain.begin();
- for (; elemItr != domain.end(); ++elemItr)
+ 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
{
- 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_MeshNode* clone = 0;
- if (!clonedNodes.count(node))
- {
- clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
- clonedNodes[node] = clone;
- }
- else
- clone = clonedNodes[node];
-
- if (isMedium)
- ln3.push_back(clone);
- else
- ln1.push_back(clone);
-
- 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);
- }
- }
-
- // --- extrude the face
-
- vector<const SMDS_MeshNode*> ln;
- SMDS_MeshVolume* vol = 0;
- vtkIdType aType = aFace->GetVtkType();
- switch (aType)
+ DownIdType edge(downIds[n], downTypes[n]);
+ if (!shapeIdToEdges[shapeId].count(edge))
{
- 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;
+ 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);
}
+ }
+ }
+ }
- if (vol)
+ 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
+ {
+ 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
{
- 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());
+ 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 < (int)nodesEdges.size(); i++ )
+ if ( nodesEdges[i] == nodeTofind )
+ break;
+ if ( i == (int)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;
+ }
+ }
+ }
- // --- modify the face
- aFace->ChangeNodes(&ln[0], ln.size());
- }
+ 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]);
}
- return true;
+ listOfListOfNodes.push_back(nodes);
+ }
+
+ // partition geom faces with blocFissure
+ // mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
+ // mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
+
+ return;
}
+
//================================================================================
/*!
* \brief Generates skin mesh (containing 2D cells) from 3D mesh
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 exsist
+ }
+ 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 = elemSetIterator( elements );
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->interlacedNodesElemIterator() ),
+ 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,
+ 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];
+ 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.Append( presentBndElems[ i ]);
}
-
+
} // loop on 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 = 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();
}
}
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:
+ {
+ const SMDS_FacePosition* fPos = static_cast< const SMDS_FacePosition* >( 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!!!!!!!!
+ const SMDS_EdgePosition* ePos = static_cast< const SMDS_EdgePosition* >( pos );
+ GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() );
+ break;
+ }
+ case SMDS_TOP_VERTEX:
+ {
+ GetMeshDS()->SetNodeOnVertex( to, from->getshapeId() );
+ break;
+ }
+ case SMDS_TOP_UNSPEC:
+ default:;
+ }
+}