/*!
* \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 );
+ }
+
+ // mark reference faces
+ GetMeshDS()->SetAllCellsNotMarked();
+ for ( const SMDS_MeshElement* refFace : theRefFaces )
+ refFace->setIsMarked( true );
- // Orient other faces
+ // erase reference faces from theFaces
+ for ( TIDSortedElemSet::iterator fIt = theFaces.begin(); fIt != theFaces.end(); )
+ if ( (*fIt)->isMarked() )
+ fIt = theFaces.erase( fIt );
+ else
+ ++fIt;
- set< const SMDS_MeshElement* > startFaces, visitedFaces;
- TIDSortedElemSet avoidSet;
- set< SMESH_TLink > checkedLinks;
- pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
+ 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 );
- startFaces.insert( theFace );
+ // 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;
}
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;
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;
}
// 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());
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();
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)
}
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;