-// Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2022 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
#include "SMESH_TryCatch.hxx" // include after OCCT headers!
+#include <smIdType.hxx>
+
#define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
using namespace std;
SMDS_MeshElement* e = 0;
int nbnode = node.size();
SMESHDS_Mesh* mesh = GetMeshDS();
- const int ID = features.myID;
+ const smIdType ID = features.myID;
switch ( features.myType ) {
case SMDSAbs_Face:
*/
//=======================================================================
-SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
- const ElemFeatures& features)
+SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<smIdType> & nodeIDs,
+ const ElemFeatures& features)
{
vector<const SMDS_MeshNode*> nodes;
nodes.reserve( nodeIDs.size() );
- vector<int>::const_iterator id = nodeIDs.begin();
+ vector<smIdType>::const_iterator id = nodeIDs.begin();
while ( id != nodeIDs.end() ) {
if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
nodes.push_back( node );
// Modify a compute state of sub-meshes which become empty
//=======================================================================
-int SMESH_MeshEditor::Remove (const list< int >& theIDs,
- const bool isNodes )
+smIdType SMESH_MeshEditor::Remove (const std::list< smIdType >& theIDs,
+ const bool isNodes )
{
ClearLastCreated();
SMESHDS_Mesh* aMesh = GetMeshDS();
set< SMESH_subMesh *> smmap;
- int removed = 0;
- list<int>::const_iterator it = theIDs.begin();
+ smIdType removed = 0;
+ list<smIdType>::const_iterator it = theIDs.begin();
for ( ; it != theIDs.end(); it++ ) {
const SMDS_MeshElement * elem;
if ( isNodes )
return removed;
}
+//================================================================================
+/*!
+ * \brief Remove a node and fill a hole appeared, by changing surrounding faces
+ */
+//================================================================================
+
+void SMESH_MeshEditor::RemoveNodeWithReconnection( const SMDS_MeshNode* node )
+{
+ if ( ! node )
+ return;
+
+ if ( node->NbInverseElements( SMDSAbs_Volume ) > 0 )
+ throw SALOME_Exception( "RemoveNodeWithReconnection() applies to 2D mesh only" );
+
+ // check that only triangles surround the node
+ for ( SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator( SMDSAbs_Face ); fIt->more(); )
+ {
+ const SMDS_MeshElement* face = fIt->next();
+ if ( face->GetGeomType() != SMDSGeom_TRIANGLE )
+ throw SALOME_Exception( "RemoveNodeWithReconnection() applies to triangle mesh only" );
+ if ( face->IsQuadratic() )
+ throw SALOME_Exception( "RemoveNodeWithReconnection() applies to linear mesh only" );
+ }
+
+ std::vector< const SMDS_MeshNode*> neighbours(2);
+ SMESH_MeshAlgos::IsOn2DBoundary( node, & neighbours );
+
+ bool toRemove = ( neighbours.size() > 2 ); // non-manifold ==> just remove
+
+ // if ( neighbours.size() == 2 ) // on boundary
+ // {
+ // // check if theNode and neighbours are on a line
+ // gp_Pnt pN = SMESH_NodeXYZ( node );
+ // gp_Pnt p0 = SMESH_NodeXYZ( neighbours[0] );
+ // gp_Pnt p1 = SMESH_NodeXYZ( neighbours[1] );
+ // double dist01 = p0.Distance( p1 );
+ // double tol = 0.01 * dist01;
+ // double distN = ( gp_Vec( p0, p1 ) ^ gp_Vec( p0, pN )).Magnitude() / dist01;
+ // bool onLine = distN < tol;
+ // toRemove = !onLine;
+ // }
+
+ if ( neighbours.empty() ) // not on boundary
+ {
+ TIDSortedElemSet linkedNodes;
+ GetLinkedNodes( node, linkedNodes, SMDSAbs_Face );
+ for ( const SMDS_MeshElement* e : linkedNodes ) neighbours.push_back( cast2Node( e ));
+ if ( neighbours.empty() )
+ toRemove = true;
+ }
+
+ if ( toRemove )
+ {
+ this->Remove( std::list< smIdType >( 1, node->GetID() ), /*isNode=*/true );
+ return;
+ }
+
+ // choose a node to replace by
+ const SMDS_MeshNode* nToReplace = nullptr;
+ SMESH_NodeXYZ nodeXYZ = node;
+ double minDist = Precision::Infinite();
+ for ( const SMDS_MeshNode* n : neighbours )
+ {
+ double dist = nodeXYZ.SquareDistance( n );
+ if ( dist < minDist )
+ {
+ minDist = dist;
+ nToReplace = n;
+ }
+ }
+
+ // remove node + replace by nToReplace
+ std::list< const SMDS_MeshNode* > nodeGroup = { nToReplace, node };
+ TListOfListOfNodes nodesToMerge( 1, nodeGroup );
+ this->MergeNodes( nodesToMerge );
+}
+
//================================================================================
/*!
* \brief Create 0D elements on all nodes of the given object.
- * \param elements - Elements on whose nodes to create 0D elements; if empty,
+ * \param elements - Elements on whose nodes to create 0D elements; if empty,
* the all mesh is treated
* \param all0DElems - returns all 0D elements found or created on nodes of \a elements
* \param duplicateElements - to add one more 0D element to a node or not
{
if( tr1->NbNodes() != tr2->NbNodes() )
return false;
+
// find the 4-th node to insert into tr1
const SMDS_MeshNode* n4 = 0;
SMDS_ElemIteratorPtr it = tr2->nodesIterator();
- int i=0;
- while ( !n4 && i<3 ) {
+ for ( int i = 0; !n4 && i < 3; ++i )
+ {
const SMDS_MeshNode * n = cast2Node( it->next() );
- i++;
bool isDiag = ( n == theNode1 || n == theNode2 );
if ( !isDiag )
n4 = n;
}
+
// Make an array of nodes to be in a quadrangle
int iNode = 0, iFirstDiag = -1;
it = tr1->nodesIterator();
- i=0;
- while ( i<3 ) {
+ for ( int i = 0; i < 3; ++i )
+ {
const SMDS_MeshNode * n = cast2Node( it->next() );
- i++;
bool isDiag = ( n == theNode1 || n == theNode2 );
if ( isDiag ) {
if ( iFirstDiag < 0 )
return true;
}
+//=======================================================================
+//function : SplitEdge
+//purpose : Replace each triangle bound by theNode1-theNode2 segment with
+// two triangles by connecting a node made on the link with a node opposite to the link.
+//=======================================================================
+
+void SMESH_MeshEditor::SplitEdge (const SMDS_MeshNode * theNode1,
+ const SMDS_MeshNode * theNode2,
+ double thePosition)
+{
+ ClearLastCreated();
+
+ SMESHDS_Mesh * mesh = GetMeshDS();
+
+ // Get triangles and segments to divide
+
+ std::vector<const SMDS_MeshNode *> diagNodes = { theNode1, theNode2 };
+ std::vector<const SMDS_MeshElement *> foundElems;
+ if ( !mesh->GetElementsByNodes( diagNodes, foundElems ) || foundElems.empty() )
+ throw SALOME_Exception( SMESH_Comment("No triangle is bound by the edge ")
+ << theNode1->GetID() << " - " << theNode2->GetID());
+
+ SMESH_MesherHelper helper( *GetMesh() );
+
+ for ( const SMDS_MeshElement * elem : foundElems )
+ {
+ SMDSAbs_ElementType type = elem->GetType();
+ switch ( type ) {
+ case SMDSAbs_Volume:
+ throw SALOME_Exception( "Can't split an edge of a volume");
+ break;
+
+ case SMDSAbs_Face:
+ if ( elem->GetGeomType() != SMDSGeom_TRIANGLE )
+ throw SALOME_Exception( "Can't split an edge of a face of type other than triangle");
+ if ( elem->IsQuadratic() )
+ {
+ helper.SetIsQuadratic( true );
+ helper.AddTLinks( static_cast< const SMDS_MeshFace*>( elem ));
+ helper.SetIsBiQuadratic( elem->GetEntityType() == SMDSEntity_BiQuad_Triangle );
+ }
+ break;
+
+ case SMDSAbs_Edge:
+ if ( elem->IsQuadratic() )
+ {
+ helper.SetIsQuadratic( true );
+ helper.AddTLinks( static_cast< const SMDS_MeshEdge*>( elem ));
+ }
+ break;
+ default:;
+ }
+ }
+
+ // Make a new node
+
+ const SMDS_MeshNode* nodeOnLink = helper.GetMediumNode( theNode1, theNode2,/*force3d=*/false );
+
+ gp_Pnt newNodeXYZ = ( SMESH_NodeXYZ( theNode1 ) * ( 1 - thePosition ) +
+ SMESH_NodeXYZ( theNode2 ) * thePosition );
+
+ const TopoDS_Shape& S = mesh->IndexToShape( nodeOnLink->GetShapeID() );
+ if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE ) // find newNodeXYZ by UV on FACE
+ {
+ Handle(ShapeAnalysis_Surface) surface = helper.GetSurface( TopoDS::Face( S ));
+ double tol = 100 * helper.MaxTolerance( S );
+ gp_Pnt2d uv = surface->ValueOfUV( newNodeXYZ, tol );
+ if ( surface->Gap() < SMESH_NodeXYZ( theNode1 ).Distance( theNode2 ))
+ {
+ newNodeXYZ = surface->Value( uv );
+ if ( SMDS_FacePositionPtr nPos = nodeOnLink->GetPosition())
+ nPos->SetParameters( uv.X(), uv.Y() );
+ }
+ }
+ if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE ) // find newNodeXYZ by param on EDGE
+ {
+ mesh->MoveNode( nodeOnLink, newNodeXYZ.X(), newNodeXYZ.Y(), newNodeXYZ.Z() );
+ double u = Precision::Infinite(), tol = 100 * helper.MaxTolerance( S ), distXYZ[4];
+ helper.ToFixNodeParameters( true );
+ if ( helper.CheckNodeU( TopoDS::Edge( S ), nodeOnLink, u, tol, /*force3D=*/false, distXYZ ))
+ newNodeXYZ.SetCoord( distXYZ[1], distXYZ[2], distXYZ[3] );
+ }
+ mesh->MoveNode( nodeOnLink, newNodeXYZ.X(), newNodeXYZ.Y(), newNodeXYZ.Z() );
+
+ // Split triangles and segments
+
+ std::vector<const SMDS_MeshNode *> nodes( 7 );
+ for ( const SMDS_MeshElement * elem : foundElems )
+ {
+ nodes.assign( elem->begin_nodes(), elem->end_nodes() );
+ nodes.resize( elem->NbCornerNodes() + 1 );
+ nodes.back() = nodes[0];
+
+ smIdType id = elem->GetID();
+ int shapeID = elem->GetShapeID();
+
+ const SMDS_MeshNode* centralNode = nullptr;
+ if ( elem->GetEntityType() == SMDSEntity_BiQuad_Triangle )
+ centralNode = elem->GetNode( 6 );
+
+ mesh->RemoveFreeElement( elem, /*sm=*/0, /*fromGroups=*/false );
+ if ( centralNode )
+ mesh->RemoveFreeNode( centralNode, /*sm=*/0, /*fromGroups=*/true );
+
+ for ( size_t i = 1; i < nodes.size(); ++i )
+ {
+ const SMDS_MeshNode* n1 = nodes[i-1];
+ const SMDS_MeshNode* n2 = nodes[i];
+ const SMDS_MeshElement* newElem;
+ if ( nodes.size() == 4 ) // triangle
+ {
+ bool isDiag1 = ( n1 == theNode1 || n1 == theNode2 );
+ bool isDiag2 = ( n2 == theNode1 || n2 == theNode2 );
+ if ( isDiag1 && isDiag2 )
+ continue;
+
+ newElem = helper.AddFace( n1, n2, nodeOnLink, id );
+ }
+ else // segment
+ {
+ newElem = helper.AddEdge( n1, nodeOnLink, id );
+ }
+ myLastCreatedElems.push_back( newElem );
+ AddToSameGroups( newElem, elem, mesh );
+ if ( shapeID )
+ mesh->SetMeshElementOnShape( newElem, shapeID );
+ id = 0;
+ }
+ }
+ return;
+}
+
+//=======================================================================
+//function : SplitFace
+//purpose : Split a face into triangles each formed by two nodes of the
+// face and a new node added at the given coordinates.
+//=======================================================================
+
+void SMESH_MeshEditor::SplitFace (const SMDS_MeshElement * theFace,
+ double theX,
+ double theY,
+ double theZ )
+{
+ ClearLastCreated();
+
+ if ( !theFace )
+ throw SALOME_Exception("Null face given");
+ if ( theFace->GetType() != SMDSAbs_Face )
+ throw SALOME_Exception("Not a face given");
+
+ SMESHDS_Mesh * mesh = GetMeshDS();
+
+ SMESH_MesherHelper helper( *GetMesh() );
+ if ( theFace->IsQuadratic() )
+ {
+ helper.SetIsQuadratic( true );
+ helper.AddTLinks( static_cast< const SMDS_MeshFace*>( theFace ));
+ }
+ const TopoDS_Shape& shape = mesh->IndexToShape( theFace->GetShapeID() );
+ helper.SetSubShape( shape );
+ helper.SetElementsOnShape( true );
+
+ // Make a new node
+
+ const SMDS_MeshNode* centralNode = nullptr;
+ if ( theFace->GetEntityType() == SMDSEntity_BiQuad_Triangle )
+ centralNode = theFace->GetNode( 6 );
+ else if ( theFace->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+ centralNode = theFace->GetNode( 8 );
+
+ if ( centralNode )
+ {
+ helper.SetIsBiQuadratic( true );
+ mesh->MoveNode( centralNode, theX, theY, theZ );
+ }
+ else
+ centralNode = helper.AddNode( theX, theY, theZ );
+
+
+ // Split theFace
+
+ std::vector<const SMDS_MeshNode *> nodes( theFace->NbNodes() + 1 );
+ nodes.assign( theFace->begin_nodes(), theFace->end_nodes() );
+ nodes.resize( theFace->NbCornerNodes() + 1 );
+ nodes.back() = nodes[0];
+
+ smIdType id = theFace->GetID();
+ int shapeID = theFace->GetShapeID();
+
+ mesh->RemoveFreeElement( theFace, /*sm=*/0, /*fromGroups=*/false );
+
+ for ( size_t i = 1; i < nodes.size(); ++i )
+ {
+ const SMDS_MeshElement* newElem = helper.AddFace( nodes[i-1], nodes[i], centralNode, id );
+
+ myLastCreatedElems.push_back( newElem );
+ AddToSameGroups( newElem, theFace, mesh );
+ if ( shapeID )
+ mesh->SetMeshElementOnShape( newElem, shapeID );
+ id = 0;
+ }
+ return;
+}
+
//=======================================================================
//function : Reorient
//purpose : Reverse theElement orientation
/*!
* \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 should be oriented according to
- * \a theDirection and whose orientation defines orientation of other faces
+ * \param theDirection - desired direction of normal of \a theRefFaces.
+ * It can be (0,0,0) in order to keep orientation of \a theRefFaces.
+ * \param theRefFaces - correctly oriented faces whose orientation defines
+ * orientation of other faces.
* \return number of reoriented faces.
*/
//================================================================================
-int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces,
- const gp_Dir& theDirection,
- const SMDS_MeshElement * theFace)
+int SMESH_MeshEditor::Reorient2D( TIDSortedElemSet & theFaces,
+ const gp_Vec& theDirection,
+ TIDSortedElemSet & theRefFaces,
+ bool theAllowNonManifold )
{
int nbReori = 0;
- if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
if ( theFaces.empty() )
{
- SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=true*/);
+ SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator();
while ( fIt->more() )
theFaces.insert( theFaces.end(), fIt->next() );
+
+ if ( theFaces.empty() )
+ return nbReori;
}
- // orient theFace according to theDirection
- gp_XYZ normal;
- SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
- if ( normal * theDirection.XYZ() < 0 )
- nbReori += Reorient( theFace );
+ // orient theRefFaces according to theDirection
+ if ( theDirection.X() != 0 || theDirection.Y() != 0 || theDirection.Z() != 0 )
+ for ( const SMDS_MeshElement* refFace : theRefFaces )
+ {
+ gp_XYZ normal;
+ SMESH_MeshAlgos::FaceNormal( refFace, normal, /*normalized=*/false );
+ if ( normal * theDirection.XYZ() < 0 )
+ nbReori += Reorient( refFace );
+ }
- // Orient other faces
+ // mark reference faces
+ GetMeshDS()->SetAllCellsNotMarked();
+ for ( const SMDS_MeshElement* refFace : theRefFaces )
+ refFace->setIsMarked( true );
- set< const SMDS_MeshElement* > startFaces, visitedFaces;
- TIDSortedElemSet avoidSet;
- set< SMESH_TLink > checkedLinks;
- pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
+ // erase reference faces from theFaces
+ for ( TIDSortedElemSet::iterator fIt = theFaces.begin(); fIt != theFaces.end(); )
+ if ( (*fIt)->isMarked() )
+ fIt = theFaces.erase( fIt );
+ else
+ ++fIt;
- if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
- theFaces.erase( theFace );
- startFaces.insert( theFace );
+ if ( theRefFaces.empty() )
+ {
+ theRefFaces.insert( *theFaces.begin() );
+ theFaces.erase( theFaces.begin() );
+ }
+
+ // Orient theFaces
+
+ // if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
+ // theFaces.erase( theFace );
int nodeInd1, nodeInd2;
- const SMDS_MeshElement* otherFace;
+ const SMDS_MeshElement* refFace, *otherFace;
vector< const SMDS_MeshElement* > facesNearLink;
vector< std::pair< int, int > > nodeIndsOfFace;
+ TIDSortedElemSet avoidSet, emptySet;
+ NCollection_Map< SMESH_TLink, SMESH_TLink > checkedLinks;
- set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
- while ( !startFaces.empty() )
+ while ( !theRefFaces.empty() )
{
- startFace = startFaces.begin();
- theFace = *startFace;
- startFaces.erase( startFace );
- if ( !visitedFaces.insert( theFace ).second )
- continue;
+ auto refFaceIt = theRefFaces.begin();
+ refFace = *refFaceIt;
+ theRefFaces.erase( refFaceIt );
avoidSet.clear();
- avoidSet.insert(theFace);
+ avoidSet.insert( refFace );
- NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 );
+ NLink link( refFace->GetNode( 0 ), nullptr );
- const int nbNodes = theFace->NbCornerNodes();
- for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
+ const int nbNodes = refFace->NbCornerNodes();
+ for ( int i = 0; i < nbNodes; ++i ) // loop on links of refFace
{
- link.second = theFace->GetNode(( i+1 ) % nbNodes );
- linkIt_isNew = checkedLinks.insert( link );
- if ( !linkIt_isNew.second )
+ link.second = refFace->GetNode(( i+1 ) % nbNodes );
+ bool isLinkVisited = checkedLinks.Contains( link );
+ if ( isLinkVisited )
{
// link has already been checked and won't be encountered more
// if the group (theFaces) is manifold
}
else
{
+ checkedLinks.Add( link );
+
facesNearLink.clear();
nodeIndsOfFace.clear();
+ TIDSortedElemSet::iterator objFaceIt = theFaces.end();
+
while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
- theFaces, avoidSet,
+ emptySet, avoidSet,
&nodeInd1, &nodeInd2 )))
- if ( otherFace != theFace)
+ {
+ if (( otherFace->isMarked() ) || // ref face
+ (( objFaceIt = theFaces.find( otherFace )) != theFaces.end() )) // object face
{
facesNearLink.push_back( otherFace );
nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
- avoidSet.insert( otherFace );
}
+ avoidSet.insert( otherFace );
+ }
if ( facesNearLink.size() > 1 )
{
// NON-MANIFOLD mesh shell !
- // select a face most co-directed with theFace,
+ if ( !theAllowNonManifold )
+ {
+ throw SALOME_Exception("Non-manifold topology of groups");
+ }
+ // select a face most co-directed with refFace,
// other faces won't be visited this time
gp_XYZ NF, NOF;
- SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
+ SMESH_MeshAlgos::FaceNormal( refFace, NF, /*normalized=*/false );
double proj, maxProj = -1;
- for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
+ for ( size_t i = 0; i < facesNearLink.size(); ++i )
+ {
SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
- if (( proj = Abs( NF * NOF )) > maxProj ) {
+ if (( proj = Abs( NF * NOF )) > maxProj )
+ {
maxProj = proj;
otherFace = facesNearLink[i];
nodeInd1 = nodeIndsOfFace[i].first;
}
}
// 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] );
+ // 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 )
{
nodeInd1 = nodeIndsOfFace.back().first;
nodeInd2 = nodeIndsOfFace.back().second;
}
- if ( otherFace && otherFace != theFace)
+ if ( otherFace )
{
- // link must be reverse in otherFace if orientation to otherFace
- // is same as that of theFace
- if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
+ // link must be reverse in otherFace if orientation of otherFace
+ // is same as that of refFace
+ if ( abs( nodeInd2 - nodeInd1 ) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
{
+ if ( otherFace->isMarked() )
+ throw SALOME_Exception("Different orientation of reference faces");
nbReori += Reorient( otherFace );
}
- startFaces.insert( otherFace );
+ if ( !otherFace->isMarked() )
+ {
+ theRefFaces.insert( otherFace );
+ if ( objFaceIt != theFaces.end() )
+ theFaces.erase( objFaceIt );
+ }
}
}
- std::swap( link.first, link.second ); // reverse the link
+ link.first = link.second; // reverse the link
+
+ } // loop on links of refFace
+
+ if ( theRefFaces.empty() && !theFaces.empty() )
+ {
+ theRefFaces.insert( *theFaces.begin() );
+ theFaces.erase( theFaces.begin() );
}
- }
+
+ } // while ( !theRefFaces.empty() )
+
return nbReori;
}
TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
: _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
+ TSplitMethod(const TSplitMethod &splitMethod)
+ : _nbSplits(splitMethod._nbSplits),
+ _nbCorners(splitMethod._nbCorners),
+ _baryNode(splitMethod._baryNode),
+ _ownConn(splitMethod._ownConn),
+ _faceBaryNode(splitMethod._faceBaryNode)
+ {
+ _connectivity = splitMethod._connectivity;
+ const_cast<TSplitMethod&>(splitMethod)._connectivity = nullptr;
+ const_cast<TSplitMethod&>(splitMethod)._ownConn = false;
+ }
bool hasFacet( const TTriangleFacet& facet ) const
{
if ( _nbCorners == 4 )
}
for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant )
{
- // check method compliancy with adjacent tetras,
+ // check method compliance with adjacent tetras,
// all found splits must be among facets of tetras described by this method
method = TSplitMethod( nbTet, connVariants[variant] );
if ( hasAdjacentSplits && method._nbSplits > 0 )
const int methodFlags,
const int facetToSplit)
{
+ TSplitMethod method;
+
// order of facets in HEX according to SMDS_VolumeTool::Hexa_F :
// B, T, L, B, R, F
const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2]
to4methods[iF]._nbSplits = 4;
to4methods[iF]._nbCorners = 6;
}
- return to4methods[iF];
+ method = to4methods[iF];
+ to4methods[iF]._connectivity = method._connectivity; // as copy ctor resets _connectivity
+ return method;
}
// else if ( methodFlags == HEXA_TO_2_PRISMS )
- TSplitMethod method;
-
const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
const int nbVariants = 2, nbSplits = 2;
// there are adjacent prism
for ( int variant = 0; variant < nbVariants; ++variant )
{
- // check method compliancy with adjacent prisms,
+ // check method compliance with adjacent prisms,
// the found prism facets must be among facets of prisms described by current method
method._nbSplits = nbSplits;
method._nbCorners = 6;
*/
//=======================================================================
- struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
+ struct TVolumeFaceKey: pair< pair< smIdType, smIdType>, pair< smIdType, smIdType> >
{
TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
{
:myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
{}
- long GetLinkID (const SMDS_MeshNode * n1,
+ smIdType GetLinkID (const SMDS_MeshNode * n1,
const SMDS_MeshNode * n2) const
{
- return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
+ return ( std::min(n1->GetID(),n2->GetID()) * myMaxID + std::max(n1->GetID(),n2->GetID()));
}
bool GetNodes (const long theLinkID,
std::swap( itNN[0], itNN[1] );
std::swap( prevNod[0], prevNod[1] );
std::swap( nextNod[0], nextNod[1] );
- std::swap( isSingleNode[0], isSingleNode[1] );
+ std::vector<bool>::swap(isSingleNode[0], isSingleNode[1]);
if ( nbSame > 0 )
sames[0] = 1 - sames[0];
iNotSameNode = 1 - iNotSameNode;
// copy offsetMesh to theTgtMesh
- int idShift = meshDS->MaxNodeID();
+ smIdType idShift = meshDS->MaxNodeID();
for ( size_t i = 0; i < new2OldNodes.size(); ++i )
if ( const SMDS_MeshNode* n = new2OldNodes[ i ].first )
{
TNodeNodeMap nodeNodeMap; // node to replace - new node
set<const SMDS_MeshElement*> elems; // all elements with changed nodes
- list< int > rmElemIds, rmNodeIds;
+ list< smIdType > rmElemIds, rmNodeIds;
vector< ElemFeatures > newElemDefs;
// Fill nodeNodeMap and elems
for ( size_t i = 0; i < newElemDefs.size(); ++i )
{
- if ( i > 0 || !mesh->ChangeElementNodes( elem,
- & newElemDefs[i].myNodes[0],
- newElemDefs[i].myNodes.size() ))
+ bool elemChanged = false;
+ if ( i == 0 )
+ {
+ if ( elem->GetGeomType() == SMDSGeom_POLYHEDRA )
+ elemChanged = mesh->ChangePolyhedronNodes( elem,
+ newElemDefs[i].myNodes,
+ newElemDefs[i].myPolyhedQuantities );
+ else
+ elemChanged = mesh->ChangeElementNodes( elem,
+ & newElemDefs[i].myNodes[0],
+ newElemDefs[i].myNodes.size() );
+ }
+ if ( i > 0 || !elemChanged )
{
if ( i == 0 )
{
// each face has to be analyzed in order to check volume validity
if ( const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( elem ))
{
+ toRemove = false;
int nbFaces = aPolyedre->NbFaces();
vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
// purpose : allow comparing elements basing on their nodes
// ========================================================
-class ComparableElement : public boost::container::flat_set< int >
+class ComparableElement : public boost::container::flat_set< smIdType >
{
- typedef boost::container::flat_set< int > int_set;
+ typedef boost::container::flat_set< smIdType > int_set;
const SMDS_MeshElement* myElem;
- int mySumID;
+ smIdType mySumID;
mutable int myGroupID;
public:
this->reserve( theElem->NbNodes() );
for ( SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); nodeIt->more(); )
{
- int id = nodeIt->next()->GetID();
+ smIdType id = nodeIt->next()->GetID();
mySumID += id;
this->insert( id );
}
static int HashCode(const ComparableElement& se, int limit )
{
- return ::HashCode( se.mySumID, limit );
+ return ::HashCode( FromSmIdType<int>(se.mySumID), limit );
}
static Standard_Boolean IsEqual(const ComparableElement& se1, const ComparableElement& se2 )
{
else elemIt = SMESHUtils::elemSetIterator( theElements );
typedef NCollection_Map< ComparableElement, ComparableElement > TMapOfElements;
- typedef std::list<int> TGroupOfElems;
+ typedef std::list<smIdType> TGroupOfElems;
TMapOfElements mapOfElements;
std::vector< TGroupOfElems > arrayOfGroups;
TGroupOfElems groupOfElems;
{
ClearLastCreated();
- typedef list<int> TListOfIDs;
+ typedef list<smIdType> TListOfIDs;
TListOfIDs rmElemIds; // IDs of elems to remove
SMESHDS_Mesh* aMesh = GetMeshDS();
TListOfListOfElementsID::iterator itGroups = equalGroups.begin();
for ( ; itGroups != equalGroups.end(); ++itGroups )
{
- list< int >& group = *itGroups;
- list< int >::iterator id = group.begin();
+ list< smIdType >& group = *itGroups;
+ list< smIdType >::iterator id = group.begin();
for ( ++id; id != group.end(); ++id )
if ( const SMDS_MeshElement* seg = GetMeshDS()->FindElement( *id ))
segments.erase( seg );
*/
//=======================================================================
-int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
- SMESH_MesherHelper& theHelper,
- const bool theForce3d)
+smIdType SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
+ SMESH_MesherHelper& theHelper,
+ const bool theForce3d)
{
//MESSAGE("convertElemToQuadratic");
- int nbElem = 0;
+ smIdType nbElem = 0;
if( !theSm ) return nbElem;
vector<int> nbNodeInFaces;
}
// get elem data needed to re-create it
//
- const int id = elem->GetID();
+ const smIdType id = elem->GetID();
const int nbNodes = elem->NbCornerNodes();
nodes.assign(elem->begin_nodes(), elem->end_nodes());
if ( aGeomType == SMDSEntity_Polyhedra )
aHelper.ToFixNodeParameters( true );
// convert elements assigned to sub-meshes
- int nbCheckedElems = 0;
+ smIdType nbCheckedElems = 0;
if ( myMesh->HasShapeToMesh() )
{
if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
}
// convert elements NOT assigned to sub-meshes
- int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
+ smIdType totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
{
aHelper.SetElementsOnShape(false);
const SMDS_MeshEdge* edge = aEdgeItr->next();
if ( !edge->IsQuadratic() )
{
- int id = edge->GetID();
+ smIdType id = edge->GetID();
const SMDS_MeshNode* n1 = edge->GetNode(0);
const SMDS_MeshNode* n2 = edge->GetNode(1);
if ( alreadyOK )
continue;
- const int id = face->GetID();
+ const smIdType id = face->GetID();
vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
continue;
}
}
- const int id = volume->GetID();
+ const smIdType id = volume->GetID();
vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
if ( type == SMDSEntity_Polyhedra )
nbNodeInFaces = static_cast<const SMDS_MeshVolume* >(volume)->GetQuantities();
if ( alreadyOK ) continue;
const SMDSAbs_ElementType type = elem->GetType();
- const int id = elem->GetID();
+ const smIdType id = elem->GetID();
const int nbNodes = elem->NbCornerNodes();
vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
//=======================================================================
/*!
* \brief Convert quadratic elements to linear ones and remove quadratic nodes
- * \return int - nb of checked elements
+ * \return smIdType - nb of checked elements
*/
//=======================================================================
-int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
- SMDS_ElemIteratorPtr theItr,
- const int /*theShapeID*/)
+smIdType SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
+ SMDS_ElemIteratorPtr theItr,
+ const int /*theShapeID*/)
{
- int nbElem = 0;
+ smIdType nbElem = 0;
SMESHDS_Mesh* meshDS = GetMeshDS();
ElemFeatures elemType;
vector<const SMDS_MeshNode *> nodes;
bool SMESH_MeshEditor::ConvertFromQuadratic()
{
- int nbCheckedElems = 0;
+ smIdType nbCheckedElems = 0;
if ( myMesh->HasShapeToMesh() )
{
if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
}
}
- int totalNbElems =
+ smIdType totalNbElems =
GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
{
if ( theElements.empty() ) return;
// collect IDs of medium nodes of theElements; some of these nodes will be removed
- set<int> mediumNodeIDs;
+ set<smIdType> mediumNodeIDs;
TIDSortedElemSet::iterator eIt = theElements.begin();
for ( ; eIt != theElements.end(); ++eIt )
{
// get remaining medium nodes
TIDSortedNodeSet mediumNodes;
- set<int>::iterator nIdsIt = mediumNodeIDs.begin();
+ set<smIdType>::iterator nIdsIt = mediumNodeIDs.begin();
for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
mediumNodes.insert( mediumNodes.end(), n );
if ( aResult != SEW_OK)
return aResult;
- list< int > nodeIDsToRemove;
+ list< smIdType > nodeIDsToRemove;
vector< const SMDS_MeshNode*> nodes;
ElemFeatures elemType;
if ( maxX < 0 )
{
_elems[0]->setIsMarked( false );
- _elems[1]->setIsMarked( true );
+ if ( _elems[1] )
+ _elems[1]->setIsMarked( true );
}
}
{
fissure.reserve( theElemsOrNodes.size() );
for ( ; elIt != theElemsOrNodes.end(); ++elIt )
+ {
fissure.push_back( std::move( FissureBorder( *elIt, elemsByFacet )));
+ if ( !fissure.back()._elems[1] )
+ fissure.pop_back();
+ }
}
if ( fissure.empty() )
return;
if ( theIsDoubleElem )
AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false ));
else
- theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() );
+ {
+ // change element nodes
+ const SMDSAbs_EntityType geomType = anElem->GetEntityType();
+ if ( geomType == SMDSEntity_Polyhedra )
+ {
+ // special treatment for polyhedron
+ const SMDS_MeshVolume* aPolyhedron = SMDS_Mesh::DownCast< SMDS_MeshVolume >( anElem );
+ if (!aPolyhedron) {
+ MESSAGE("Warning: bad volumic element");
+ return false;
+ }
+ theMeshDS->ChangePolyhedronNodes( anElem, newNodes, aPolyhedron->GetQuantities() );
+ }
+ else
+ // standard entity type
+ theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() );
+ }
res = true;
}
\brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
This method is the first step of DoubleNodeElemGroupsInRegion.
\param theElems - list of groups of elements (edges or faces) to be replicated
- \param theNodesNot - list of groups of nodes not to replicated
+ \param theNodesNot - list of groups of nodes not to replicate
\param theShape - shape to detect affected elements (element which geometric center
located on or inside shape). If the shape is null, detection is done on faces orientations
(select elements with a gravity center on the side given by faces normals).
// build the list of nodes shared by 2 or more domains, with their domain indexes
std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
- std::map<int,int>celldom; // cell vtkId --> domain
+ 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();
//MESSAGE(".. Number of domains :"<<theElems.size());
const SMDS_MeshElement* anElem = *elemItr;
if (!anElem)
continue;
- int vtkId = anElem->GetVtkID();
+ vtkIdType vtkId = anElem->GetVtkID();
//MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID());
int neighborsVtkIds[NBMAXNEIGHBORS];
int downIds[NBMAXNEIGHBORS];
int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
for (int n = 0; n < nbNeighbors; n++)
{
- int smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
+ smIdType smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared
{
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)
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)
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();
const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom];
for ( int ivol = 0; ivol < nbvol; ivol++ )
{
- int smdsId = meshDS->FromVtkToSmds(vtkVolIds[ivol]);
+ smIdType smdsId = meshDS->FromVtkToSmds(vtkVolIds[ivol]);
const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
if (domain.count(elem))
{
std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
//MESSAGE(".. Creation of elements: simple junction");
- if (createJointElems)
+ if ( createJointElems )
{
string joints2DName = "joints2D";
mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str());
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> domvol = itface->second;
std::map<int, int>::iterator itdom = domvol.begin();
- int dom1 = itdom->first;
+ int dom1 = itdom->first;
int vtkVolId = itdom->second;
itdom++;
- int dom2 = itdom->first;
+ int dom2 = itdom->first;
SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
nodeQuadDomains);
stringstream grpname;
std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
for (; ite != edgesMultiDomains.end(); ++ite)
{
- vector<int> nodes = ite->first;
+ vector<int> nodes = ite->first;
vector<int> orderDom = ite->second;
vector<vtkIdType> orderedNodes;
if (nodes.size() == 2)
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();
//MESSAGE(".. Modification of elements");
+ SMDSAbs_ElementType domainType = (*theElems[0].begin())->GetType();
for (int idomain = idom0; idomain < nbDomains; idomain++)
{
std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
continue; // new cells: not to be modified
DownIdType aCell(downId, vtkType);
int volParents[1000];
- int nbvol = grid->GetParentVolumes(volParents, vtkId);
+ int nbvol = 0;
+ nbvol = grid->GetParentVolumes(volParents, vtkId);
+ if ( domainType == SMDSAbs_Volume )
+ {
+ nbvol = grid->GetParentVolumes(volParents, vtkId);
+ }
+ else // domainType == SMDSAbs_Face
+ {
+ const int nbFaces = grid->getDownArray(vtkType)->getNumberOfUpCells(downId);
+ const int *upCells = grid->getDownArray(vtkType)->getUpCells(downId);
+ const unsigned char* upTypes = grid->getDownArray(vtkType)->getUpTypes(downId);
+ for (int i=0; i< nbFaces; i++)
+ {
+ int vtkFaceId = grid->getDownArray( upTypes[i] )->getVtkCellId(upCells[i]);
+ if (vtkFaceId >= 0)
+ volParents[nbvol++] = vtkFaceId;
+ }
+ }
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);
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<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 ( size_t idom = 0; idom < theElems.size(); idom++ )
{
std::set<int> setOfVolToCheck;
std::vector<gp_Pnt> gpnts;
- gpnts.clear();
if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
{
// Fill the group of inside volumes
std::map<int, double> mapOfNodeDistance2;
- mapOfNodeDistance2.clear();
std::set<int> setOfOutsideVol;
while (!setOfVolToCheck.empty())
{
// project polylines on subshapes, and partition, to get geom faces
std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
- std::set<int> emptySet;
- emptySet.clear();
- std::set<int> shapeIds;
+ std::set<int> shapeIds;
SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
while (itelem->more())
int vtkId = elem->GetVtkID();
if (!shapeIdToVtkIdSet.count(shapeId))
{
- shapeIdToVtkIdSet[shapeId] = emptySet;
shapeIds.insert(shapeId);
}
shapeIdToVtkIdSet[shapeId].insert(vtkId);
std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
std::set<DownIdType, DownIdCompare> emptyEdges;
- emptyEdges.clear();
std::map<int, std::set<int> >::iterator itShape = shapeIdToVtkIdSet.begin();
for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
{
if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
continue;
- int smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
+ smIdType smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
{
}
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;